Fix: userinfo (#15)
* add idea to gitignore * working userinfo * cleanup * tests
This commit is contained in:
parent
5af734d72f
commit
2b9f7dfd18
8 changed files with 225 additions and 73 deletions
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue