1package ldap 2 3import ( 4 "context" 5 "fmt" 6 7 "github.com/hashicorp/vault/sdk/framework" 8 "github.com/hashicorp/vault/sdk/helper/cidrutil" 9 "github.com/hashicorp/vault/sdk/helper/policyutil" 10 "github.com/hashicorp/vault/sdk/logical" 11) 12 13func pathLogin(b *backend) *framework.Path { 14 return &framework.Path{ 15 Pattern: `login/(?P<username>.+)`, 16 Fields: map[string]*framework.FieldSchema{ 17 "username": &framework.FieldSchema{ 18 Type: framework.TypeString, 19 Description: "DN (distinguished name) to be used for login.", 20 }, 21 22 "password": &framework.FieldSchema{ 23 Type: framework.TypeString, 24 Description: "Password for this user.", 25 }, 26 }, 27 28 Callbacks: map[logical.Operation]framework.OperationFunc{ 29 logical.UpdateOperation: b.pathLogin, 30 logical.AliasLookaheadOperation: b.pathLoginAliasLookahead, 31 }, 32 33 HelpSynopsis: pathLoginSyn, 34 HelpDescription: pathLoginDesc, 35 } 36} 37 38func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { 39 username := d.Get("username").(string) 40 if username == "" { 41 return nil, fmt.Errorf("missing username") 42 } 43 44 return &logical.Response{ 45 Auth: &logical.Auth{ 46 Alias: &logical.Alias{ 47 Name: username, 48 }, 49 }, 50 }, nil 51} 52 53func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { 54 cfg, err := b.Config(ctx, req) 55 if err != nil { 56 return nil, err 57 } 58 if cfg == nil { 59 return logical.ErrorResponse("auth method not configured"), nil 60 } 61 62 // Check for a CIDR match. 63 if len(cfg.TokenBoundCIDRs) > 0 { 64 if req.Connection == nil { 65 b.Logger().Warn("token bound CIDRs found but no connection information available for validation") 66 return nil, logical.ErrPermissionDenied 67 } 68 if !cidrutil.RemoteAddrIsOk(req.Connection.RemoteAddr, cfg.TokenBoundCIDRs) { 69 return nil, logical.ErrPermissionDenied 70 } 71 } 72 73 username := d.Get("username").(string) 74 password := d.Get("password").(string) 75 76 policies, resp, groupNames, err := b.Login(ctx, req, username, password) 77 // Handle an internal error 78 if err != nil { 79 return nil, err 80 } 81 if resp != nil { 82 // Handle a logical error 83 if resp.IsError() { 84 return resp, nil 85 } 86 } else { 87 resp = &logical.Response{} 88 } 89 90 auth := &logical.Auth{ 91 Metadata: map[string]string{ 92 "username": username, 93 }, 94 InternalData: map[string]interface{}{ 95 "password": password, 96 }, 97 DisplayName: username, 98 Alias: &logical.Alias{ 99 Name: username, 100 }, 101 } 102 103 cfg.PopulateTokenAuth(auth) 104 105 // Add in configured policies from mappings 106 if len(policies) > 0 { 107 auth.Policies = append(auth.Policies, policies...) 108 } 109 110 resp.Auth = auth 111 112 for _, groupName := range groupNames { 113 if groupName == "" { 114 continue 115 } 116 resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{ 117 Name: groupName, 118 }) 119 } 120 return resp, nil 121} 122 123func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) { 124 cfg, err := b.Config(ctx, req) 125 if err != nil { 126 return nil, err 127 } 128 if cfg == nil { 129 return logical.ErrorResponse("auth method not configured"), nil 130 } 131 132 username := req.Auth.Metadata["username"] 133 password := req.Auth.InternalData["password"].(string) 134 135 loginPolicies, resp, groupNames, err := b.Login(ctx, req, username, password) 136 if len(loginPolicies) == 0 { 137 return resp, err 138 } 139 finalPolicies := cfg.TokenPolicies 140 if len(loginPolicies) > 0 { 141 finalPolicies = append(finalPolicies, loginPolicies...) 142 } 143 144 if !policyutil.EquivalentPolicies(finalPolicies, req.Auth.TokenPolicies) { 145 return nil, fmt.Errorf("policies have changed, not renewing") 146 } 147 148 resp.Auth = req.Auth 149 resp.Auth.Period = cfg.TokenPeriod 150 resp.Auth.TTL = cfg.TokenTTL 151 resp.Auth.MaxTTL = cfg.TokenMaxTTL 152 153 // Remove old aliases 154 resp.Auth.GroupAliases = nil 155 156 for _, groupName := range groupNames { 157 resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{ 158 Name: groupName, 159 }) 160 } 161 162 return resp, nil 163} 164 165const pathLoginSyn = ` 166Log in with a username and password. 167` 168 169const pathLoginDesc = ` 170This endpoint authenticates using a username and password. Please be sure to 171read the note on escaping from the path-help for the 'config' endpoint. 172` 173