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
}
示例#3
0
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
}
示例#5
0
// 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
}
示例#7
0
// 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)
		}
	}
}