Fix: userinfo (#15)

* add idea to gitignore

* working userinfo

* cleanup

* tests
This commit is contained in:
livio-a 2020-03-06 17:14:30 +01:00 committed by GitHub
parent 5af734d72f
commit 2b9f7dfd18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 225 additions and 73 deletions

View file

@ -154,18 +154,33 @@ func (mr *MockStorageMockRecorder) GetSigningKey(arg0, arg1, arg2, arg3 interfac
}
// GetUserinfoFromScopes mocks base method
func (m *MockStorage) GetUserinfoFromScopes(arg0 context.Context, arg1 []string) (*oidc.Userinfo, error) {
func (m *MockStorage) GetUserinfoFromScopes(arg0 context.Context, arg1 string, arg2 []string) (*oidc.Userinfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserinfoFromScopes", arg0, arg1)
ret := m.ctrl.Call(m, "GetUserinfoFromScopes", arg0, arg1, arg2)
ret0, _ := ret[0].(*oidc.Userinfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserinfoFromScopes indicates an expected call of GetUserinfoFromScopes
func (mr *MockStorageMockRecorder) GetUserinfoFromScopes(arg0, arg1 interface{}) *gomock.Call {
func (mr *MockStorageMockRecorder) GetUserinfoFromScopes(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserinfoFromScopes", reflect.TypeOf((*MockStorage)(nil).GetUserinfoFromScopes), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserinfoFromScopes", reflect.TypeOf((*MockStorage)(nil).GetUserinfoFromScopes), arg0, arg1, arg2)
}
// GetUserinfoFromToken mocks base method
func (m *MockStorage) GetUserinfoFromToken(arg0 context.Context, arg1 string) (*oidc.Userinfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserinfoFromToken", arg0, arg1)
ret0, _ := ret[0].(*oidc.Userinfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserinfoFromToken indicates an expected call of GetUserinfoFromToken
func (mr *MockStorageMockRecorder) GetUserinfoFromToken(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserinfoFromToken", reflect.TypeOf((*MockStorage)(nil).GetUserinfoFromToken), arg0, arg1)
}
// Health mocks base method

View file

@ -26,7 +26,8 @@ type AuthStorage interface {
type OPStorage interface {
GetClientByClientID(context.Context, string) (Client, error)
AuthorizeClientIDSecret(context.Context, string, string) error
GetUserinfoFromScopes(context.Context, []string) (*oidc.Userinfo, error)
GetUserinfoFromScopes(context.Context, string, []string) (*oidc.Userinfo, error)
GetUserinfoFromToken(context.Context, string) (*oidc.Userinfo, error)
}
type Storage interface {

View file

@ -24,7 +24,7 @@ func CreateTokenResponse(ctx context.Context, authReq AuthRequest, client Client
return nil, err
}
}
idToken, err := CreateIDToken(creator.Issuer(), authReq, client.IDTokenLifetime(), accessToken, code, creator.Signer())
idToken, err := CreateIDToken(ctx, creator.Issuer(), authReq, client.IDTokenLifetime(), accessToken, code, creator.Storage(), creator.Signer())
if err != nil {
return nil, err
}
@ -71,12 +71,15 @@ func CreateJWT(issuer string, authReq AuthRequest, exp time.Time, id string, sig
return signer.SignAccessToken(claims)
}
func CreateIDToken(issuer string, authReq AuthRequest, validity time.Duration, accessToken, code string, signer Signer) (string, error) {
func CreateIDToken(ctx context.Context, issuer string, authReq AuthRequest, validity time.Duration, accessToken, code string, storage Storage, signer Signer) (string, error) {
var err error
exp := time.Now().UTC().Add(validity)
userinfo, err := storage.GetUserinfoFromScopes(ctx, authReq.GetSubject(), authReq.GetScopes())
if err != nil {
}
claims := &oidc.IDTokenClaims{
Issuer: issuer,
Subject: authReq.GetSubject(),
Audiences: authReq.GetAudience(),
Expiration: exp,
IssuedAt: time.Now().UTC(),
@ -85,6 +88,7 @@ func CreateIDToken(issuer string, authReq AuthRequest, validity time.Duration, a
AuthenticationContextClassReference: authReq.GetACR(),
AuthenticationMethodsReferences: authReq.GetAMR(),
AuthorizedParty: authReq.GetClientID(),
Userinfo: *userinfo,
}
if accessToken != "" {
claims.AccessTokenHash, err = oidc.ClaimHash(accessToken, signer.SignatureAlgorithm())

View file

@ -1,21 +1,33 @@
package op
import (
"errors"
"net/http"
"strings"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/utils"
"github.com/gorilla/schema"
)
type UserinfoProvider interface {
Decoder() *schema.Decoder
Crypto() Crypto
Storage() Storage
}
func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoProvider) {
scopes, err := ScopesFromAccessToken(w, r)
accessToken, err := getAccessToken(r, userinfoProvider.Decoder())
if err != nil {
http.Error(w, "access token missing", http.StatusUnauthorized)
return
}
info, err := userinfoProvider.Storage().GetUserinfoFromScopes(r.Context(), scopes)
tokenID, err := userinfoProvider.Crypto().Decrypt(accessToken)
if err != nil {
http.Error(w, "access token missing", http.StatusUnauthorized)
return
}
info, err := userinfoProvider.Storage().GetUserinfoFromToken(r.Context(), tokenID)
if err != nil {
utils.MarshalJSON(w, err)
return
@ -23,6 +35,23 @@ func Userinfo(w http.ResponseWriter, r *http.Request, userinfoProvider UserinfoP
utils.MarshalJSON(w, info)
}
func ScopesFromAccessToken(w http.ResponseWriter, r *http.Request) ([]string, error) {
return []string{}, nil
func getAccessToken(r *http.Request, decoder *schema.Decoder) (string, error) {
authHeader := r.Header.Get("authorization")
if authHeader != "" {
parts := strings.Split(authHeader, "Bearer ")
if len(parts) != 2 {
return "", errors.New("invalid auth header")
}
return parts[1], nil
}
err := r.ParseForm()
if err != nil {
return "", errors.New("unable to parse request")
}
req := new(oidc.UserInfoRequest)
err = decoder.Decode(req, r.Form)
if err != nil {
return "", errors.New("unable to parse request")
}
return req.AccessToken, nil
}