forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 2
/
path_login.go
128 lines (111 loc) · 3.85 KB
/
path_login.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package approle
import (
"context"
"fmt"
"strings"
"time"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathLogin(b *backend) *framework.Path {
return &framework.Path{
Pattern: "login$",
Fields: map[string]*framework.FieldSchema{
"role_id": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Unique identifier of the Role. Required to be supplied when the 'bind_secret_id' constraint is set.",
},
"secret_id": &framework.FieldSchema{
Type: framework.TypeString,
Default: "",
Description: "SecretID belong to the App role",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathLoginUpdate,
logical.AliasLookaheadOperation: b.pathLoginUpdateAliasLookahead,
},
HelpSynopsis: pathLoginHelpSys,
HelpDescription: pathLoginHelpDesc,
}
}
func (b *backend) pathLoginUpdateAliasLookahead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
roleID := strings.TrimSpace(data.Get("role_id").(string))
if roleID == "" {
return nil, fmt.Errorf("missing role_id")
}
return &logical.Response{
Auth: &logical.Auth{
Alias: &logical.Alias{
Name: roleID,
},
},
}, nil
}
// Returns the Auth object indicating the authentication and authorization information
// if the credentials provided are validated by the backend.
func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
role, roleName, metadata, _, err := b.validateCredentials(ctx, req, data)
if err != nil || role == nil {
return logical.ErrorResponse(fmt.Sprintf("failed to validate credentials: %v", err)), nil
}
// Always include the role name, for later filtering
metadata["role_name"] = roleName
auth := &logical.Auth{
NumUses: role.TokenNumUses,
Period: role.Period,
InternalData: map[string]interface{}{
"role_name": roleName,
},
Metadata: metadata,
Policies: role.Policies,
LeaseOptions: logical.LeaseOptions{
Renewable: true,
TTL: role.TokenTTL,
},
Alias: &logical.Alias{
Name: role.RoleID,
},
}
return &logical.Response{
Auth: auth,
}, nil
}
// Invoked when the token issued by this backend is attempting a renewal.
func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
roleName := req.Auth.InternalData["role_name"].(string)
if roleName == "" {
return nil, fmt.Errorf("failed to fetch role_name during renewal")
}
lock := b.roleLock(roleName)
lock.RLock()
defer lock.RUnlock()
// Ensure that the Role still exists.
role, err := b.roleEntry(ctx, req.Storage, strings.ToLower(roleName))
if err != nil {
return nil, fmt.Errorf("failed to validate role %s during renewal:%s", roleName, err)
}
if role == nil {
return nil, fmt.Errorf("role %s does not exist during renewal", roleName)
}
// If a period is provided, set that as part of resp.Auth.Period and return a
// response immediately. Let expiration manager handle renewal from there on.
if role.Period > time.Duration(0) {
resp := &logical.Response{
Auth: req.Auth,
}
resp.Auth.Period = role.Period
return resp, nil
}
return framework.LeaseExtend(role.TokenTTL, role.TokenMaxTTL, b.System())(ctx, req, data)
}
const pathLoginHelpSys = "Issue a token based on the credentials supplied"
const pathLoginHelpDesc = `
While the credential 'role_id' is required at all times,
other credentials required depends on the properties App role
to which the 'role_id' belongs to. The 'bind_secret_id'
constraint (enabled by default) on the App role requires the
'secret_id' credential to be presented.
'role_id' is fetched using the 'role/<role_name>/role_id'
endpoint and 'secret_id' is fetched using the 'role/<role_name>/secret_id'
endpoint.`