zitadel/internal/api/oidc/auth_request.go
Livio Amstutz a321d850ae
feat: project roles (#843)
* fix logging

* token verification

* feat: assert roles

* feat: add project role assertion on project and token type on app

* id and access token role assertion

* add project role check

* user grant required step in login

* update library

* fix merge

* fix merge

* fix merge

* update oidc library

* fix tests

* add tests for GrantRequiredStep

* add missing field ProjectRoleCheck on project view model

* fix project create

* fix project create
2020-10-16 07:49:38 +02:00

134 lines
4.2 KiB
Go

package oidc
import (
"context"
"fmt"
"strings"
"time"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op"
"gopkg.in/square/go-jose.v2"
"github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
)
func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) {
userAgentID, ok := middleware.UserAgentIDFromCtx(ctx)
if !ok {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
}
app, err := o.repo.ApplicationByClientID(ctx, req.ClientID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal")
}
req.Scopes, err = o.assertProjectRoleScopes(app, req.Scopes)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-Gqrfg", "Errors.Internal")
}
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
if err != nil {
return nil, err
}
return AuthRequestFromBusiness(resp)
}
func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequest, error) {
userAgentID, ok := middleware.UserAgentIDFromCtx(ctx)
if !ok {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-D3g21", "no user agent id")
}
resp, err := o.repo.AuthRequestByIDCheckLoggedIn(ctx, id, userAgentID)
if err != nil {
return nil, err
}
return AuthRequestFromBusiness(resp)
}
func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.AuthRequest, error) {
resp, err := o.repo.AuthRequestByCode(ctx, code)
if err != nil {
return nil, err
}
return AuthRequestFromBusiness(resp)
}
func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error {
userAgentID, ok := middleware.UserAgentIDFromCtx(ctx)
if !ok {
return errors.ThrowPreconditionFailed(nil, "OIDC-Dgus2", "no user agent id")
}
return o.repo.SaveAuthCode(ctx, id, code, userAgentID)
}
func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) error {
return o.repo.DeleteAuthRequest(ctx, id)
}
func (o *OPStorage) CreateToken(ctx context.Context, req op.TokenRequest) (string, time.Time, error) {
var userAgentID, applicationID string
authReq, ok := req.(*AuthRequest)
if ok {
userAgentID = authReq.AgentID
applicationID = authReq.ApplicationID
}
resp, err := o.repo.CreateToken(ctx, userAgentID, applicationID, req.GetSubject(), req.GetAudience(), req.GetScopes(), o.defaultAccessTokenLifetime) //PLANNED: lifetime from client
if err != nil {
return "", time.Time{}, err
}
return resp.TokenID, resp.Expiration, nil
}
func grantsToScopes(grants []*grant_model.UserGrantView) []string {
scopes := make([]string, 0)
for _, grant := range grants {
for _, role := range grant.RoleKeys {
scopes = append(scopes, fmt.Sprintf("%v:%v", grant.ResourceOwner, role))
}
}
return scopes
}
func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) error {
userAgentID, ok := middleware.UserAgentIDFromCtx(ctx)
if !ok {
return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id")
}
return o.repo.SignOut(ctx, userAgentID)
}
func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) {
o.repo.GetSigningKey(ctx, keyCh, errCh, timer)
}
func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) {
return o.repo.GetKeySet(ctx)
}
func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error {
return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm)
}
func (o *OPStorage) assertProjectRoleScopes(app *proj_model.ApplicationView, scopes []string) ([]string, error) {
if !app.ProjectRoleAssertion {
return scopes, nil
}
for _, scope := range scopes {
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
return scopes, nil
}
}
roles, err := o.repo.ProjectRolesByProjectID(app.ProjectID)
if err != nil {
return nil, err
}
for _, role := range roles {
scopes = append(scopes, ScopeProjectRolePrefix+role.Key)
}
return scopes, nil
}