func (a *Authenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) { username := "" for _, header := range a.config.UserNameHeaders { header = strings.TrimSpace(header) if len(header) == 0 { continue } username = req.Header.Get(header) if len(username) != 0 { break } } if len(username) == 0 { return nil, false, nil } identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username) user, err := a.mapper.UserFor(identity) if err != nil { return nil, false, err } glog.V(4).Infof("Got userIdentityMapping: %#v", user) return user, true, nil }
func makeIdentityInfo(providerName, providerUserName string, extra map[string]string) authapi.UserIdentityInfo { info := authapi.NewDefaultUserIdentityInfo("idp", "bob") if extra != nil { info.Extra = extra } return info }
func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) { a.loadIfNeeded() if len(username) > 255 { username = username[:255] } if strings.Contains(username, ":") { return nil, false, errors.New("Usernames may not contain : characters") } hash, ok := a.usernames[username] if !ok { return nil, false, nil } if ok, err := testPassword(password, hash); !ok || err != nil { return nil, false, err } identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username) user, err := a.mapper.UserFor(identity) glog.V(4).Infof("Got userIdentityMapping: %#v", user) if err != nil { return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err) } return user, true, nil }
// AuthenticatePassword approves any login attempt with non-blank username and password func (a alwaysAcceptPasswordAuthenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) { if username == "" || password == "" { return nil, false, nil } identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username) user, err := a.identityMapper.UserFor(identity) glog.V(4).Infof("Got userIdentityMapping: %#v", user) if err != nil { return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err) } return user, true, nil }
// GetUserIdentity implements external/interfaces/Provider.GetUserIdentity func (p provider) GetUserIdentity(data *osincli.AccessData) (authapi.UserIdentityInfo, bool, error) { req, _ := http.NewRequest("GET", githubUserApiURL, nil) req.Header.Set("Authorization", fmt.Sprintf("bearer %s", data.AccessToken)) res, err := http.DefaultClient.Do(req) if err != nil { return nil, false, err } body, err := ioutil.ReadAll(res.Body) if err != nil { return nil, false, err } userdata := githubUser{} err = json.Unmarshal(body, &userdata) if err != nil { return nil, false, err } if userdata.ID == 0 { return nil, false, errors.New("Could not retrieve GitHub id") } identity := authapi.NewDefaultUserIdentityInfo(p.providerName, fmt.Sprintf("%d", userdata.ID)) if len(userdata.Name) > 0 { identity.Extra[authapi.IdentityDisplayNameKey] = userdata.Name } if len(userdata.Login) > 0 { identity.Extra[authapi.IdentityPreferredUsernameKey] = userdata.Login } if len(userdata.Email) > 0 { identity.Extra[authapi.IdentityEmailKey] = userdata.Email } glog.V(4).Infof("Got identity=%#v", identity) return identity, true, nil }
func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) { areq := a.client.NewAccessRequest(osincli.PASSWORD, nil) areq.CustomParameters["username"] = username areq.CustomParameters["password"] = password token, err := areq.GetToken() if err != nil { if oerr, ok := err.(*osincli.Error); ok { if oerr.Id == osincli.E_ACCESS_DENIED { return nil, false, nil } } return nil, false, err } identity := authapi.NewDefaultUserIdentityInfo(a.providerName, username) identity.Extra["token"] = token.AccessToken user, err := a.mapper.UserFor(identity) glog.V(4).Infof("Got userIdentityMapping: %#v", user) if err != nil { return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err) } return user, true, nil }
// GetUserIdentity implements external/interfaces/Provider.GetUserIdentity func (p provider) GetUserIdentity(data *osincli.AccessData) (authapi.UserIdentityInfo, bool, error) { // Token response MUST include id_token // http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse idToken, ok := data.ResponseData["id_token"].(string) if !ok { return nil, false, fmt.Errorf("No id_token returned in %v", data.ResponseData) } // id_token MUST be a valid JWT idTokenClaims, err := decodeJWT(idToken) if err != nil { return nil, false, err } if p.IDTokenValidator != nil { if err := p.IDTokenValidator(idTokenClaims); err != nil { return nil, false, err } } // TODO: validate JWT // http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation // id_token MUST contain a sub claim as the subject identifier // http://openid.net/specs/openid-connect-core-1_0.html#IDToken idTokenSubject, ok := idTokenClaims[SubjectClaim].(string) if !ok { return nil, false, fmt.Errorf("id_token did not contain a 'sub' claim: %#v", idTokenClaims) } // Use id_token claims by default claims := idTokenClaims // If we have a userinfo URL, use it to get more detailed claims if len(p.UserInfoURL) != 0 { userInfoClaims, err := fetchUserInfo(p.UserInfoURL, data.AccessToken, p.transport) if err != nil { return nil, false, err } // The sub (subject) Claim MUST always be returned in the UserInfo Response. // http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse userInfoSubject, ok := userInfoClaims[SubjectClaim].(string) if !ok { return nil, false, fmt.Errorf("userinfo response did not contain a 'sub' claim: %#v", userInfoClaims) } // The sub Claim in the UserInfo Response MUST be verified to exactly match the sub Claim in the ID Token; // if they do not match, the UserInfo Response values MUST NOT be used. // http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse if userInfoSubject != idTokenSubject { return nil, false, fmt.Errorf("userinfo 'sub' claim (%s) did not match id_token 'sub' claim (%s)", userInfoSubject, idTokenSubject) } // Merge in userinfo claims in case id_token claims contained some that userinfo did not for k, v := range userInfoClaims { claims[k] = v } } id, _ := getClaimValue(claims, p.IDClaims) if id == "" { return nil, false, fmt.Errorf("Could not retrieve id claim for %#v", p.IDClaims) } identity := authapi.NewDefaultUserIdentityInfo(p.providerName, id) if preferredUsername, _ := getClaimValue(claims, p.PreferredUsernameClaims); len(preferredUsername) != 0 { identity.Extra[authapi.IdentityPreferredUsernameKey] = preferredUsername } if email, _ := getClaimValue(claims, p.EmailClaims); len(email) != 0 { identity.Extra[authapi.IdentityEmailKey] = email } if name, _ := getClaimValue(claims, p.NameClaims); len(name) != 0 { identity.Extra[authapi.IdentityDisplayNameKey] = name } glog.V(4).Infof("identity=%v", identity) return identity, true, nil }
func (a *Authenticator) AuthenticatePassword(username, password string) (user.Info, bool, error) { req, err := http.NewRequest("GET", a.url, nil) if err != nil { return nil, false, err } req.SetBasicAuth(username, password) req.Header.Set("Accept", "application/json") resp, err := a.client.Do(req) if err != nil { return nil, false, err } if resp.StatusCode == http.StatusUnauthorized { return nil, false, nil } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, false, err } remoteError := RemoteError{} json.Unmarshal(body, &remoteError) if remoteError.Error != "" { return nil, false, errors.New(remoteError.Error) } if resp.StatusCode != http.StatusOK { return nil, false, fmt.Errorf("An error occurred while authenticating (%d)", resp.StatusCode) } remoteUserData := RemoteUserData{} err = json.Unmarshal(body, &remoteUserData) if err != nil { return nil, false, err } if len(remoteUserData.Subject) == 0 { return nil, false, errors.New("Could not retrieve user data") } identity := authapi.NewDefaultUserIdentityInfo(a.providerName, remoteUserData.Subject) if len(remoteUserData.Name) > 0 { identity.Extra[authapi.IdentityDisplayNameKey] = remoteUserData.Name } if len(remoteUserData.PreferredUsername) > 0 { identity.Extra[authapi.IdentityPreferredUsernameKey] = remoteUserData.PreferredUsername } if len(remoteUserData.Email) > 0 { identity.Extra[authapi.IdentityEmailKey] = remoteUserData.Email } user, err := a.mapper.UserFor(identity) glog.V(4).Infof("Got userIdentityMapping: %#v", user) if err != nil { return nil, false, fmt.Errorf("Error creating or updating mapping for: %#v due to %v", identity, err) } return user, true, nil }
func TestProvisionConflictingIdentity(t *testing.T) { expectedProviderName := "myprovidername" expectedProviderUserName := "******" expectedIdentityName := "myprovidername:myusername" expectedUserName := "******" expectedUserUID := "myuseruid" // Expect identity to fully specify a user name and uid expectedCreateIdentity := &api.Identity{ ObjectMeta: kapi.ObjectMeta{Name: expectedIdentityName}, ProviderName: expectedProviderName, ProviderUserName: expectedProviderUserName, User: kapi.ObjectReference{ Name: expectedUserName, UID: types.UID(expectedUserUID), }, Extra: map[string]string{}, } // Expect user to be populated with the right name, display name, and identity expectedCreateUser := &api.User{ ObjectMeta: kapi.ObjectMeta{ Name: expectedUserName, }, Identities: []string{expectedIdentityName}, } // Return a user containing a uid expectedCreateUserResult := &api.User{ ObjectMeta: kapi.ObjectMeta{ Name: expectedUserName, UID: types.UID(expectedUserUID), }, Identities: []string{expectedIdentityName}, } expectedActions := []test.Action{ {"GetIdentity", expectedIdentityName}, {"GetUser", expectedProviderUserName}, {"GetUser", expectedProviderUserName + "2"}, {"GetUser", expectedProviderUserName + "3"}, {"CreateUser", expectedCreateUser}, {"CreateIdentity", expectedCreateIdentity}, } actions := []test.Action{} identityRegistry := &test.IdentityRegistry{ Create: expectedCreateIdentity, Actions: &actions, } userRegistry := &test.UserRegistry{ Get: map[string]*api.User{ expectedProviderUserName: {}, expectedProviderUserName + "2": {}, }, Create: expectedCreateUserResult, Actions: &actions, } identityMapper := NewAlwaysCreateUserIdentityToUserMapper(identityRegistry, userRegistry) identity := authapi.NewDefaultUserIdentityInfo(expectedProviderName, expectedProviderUserName) identityMapper.UserFor(identity) for i, action := range actions { if len(expectedActions) <= i { t.Fatalf("Expected %d actions, got extras: %#v", len(expectedActions), actions[i:]) } expectedAction := expectedActions[i] if !reflect.DeepEqual(expectedAction, action) { t.Fatalf("Expected\n\t%s %#v\nGot\n\t%s %#v", expectedAction.Name, expectedAction.Object, action.Name, action.Object) } } }