fix(app): move queries to query package (#2612)

* fix: move queries to query package

* fix(auth): switch project role requests to query pkg

* refactor: delete unused project role code

* remove repo

* implement sql queries

* fix(database): oidc config change type to int2

* fix(queries): implement app queries

* refactor: simplify code

* fix: correct app query

* Update app.go

* fix token check

* fix mock

* test: app prepares

* test: oidc compliance

* test: OIDCOriginAllowList

* fix: converter

* resolve unsupported oidc version

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Silvan
2021-11-26 07:57:05 +01:00
committed by GitHub
parent a9035def0f
commit 3473156c7e
39 changed files with 3150 additions and 1066 deletions

View File

@@ -47,7 +47,7 @@ type API struct {
type health interface {
Health(ctx context.Context) error
IamByID(ctx context.Context) (*iam_model.IAM, error)
VerifierClientID(ctx context.Context, appName string) (string, error)
VerifierClientID(ctx context.Context, appName string) (string, string, error)
}
type auth interface {
@@ -159,7 +159,7 @@ func handleValidate(checks []ValidationFunction) func(w http.ResponseWriter, r *
}
func (a *API) handleClientID(w http.ResponseWriter, r *http.Request) {
id, err := a.health.VerifierClientID(r.Context(), "Zitadel Console")
id, _, err := a.health.VerifierClientID(r.Context(), "Zitadel Console")
if err != nil {
http_util.MarshalJSON(w, nil, err, http.StatusPreconditionFailed)
return

View File

@@ -15,7 +15,7 @@ type testVerifier struct {
memberships []*Membership
}
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, string, error) {
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID, projectID string) (string, string, string, string, string, error) {
return "userID", "agentID", "clientID", "de", "orgID", nil
}
func (v *testVerifier) SearchMyMemberships(ctx context.Context) ([]*Membership, error) {
@@ -30,8 +30,8 @@ func (v *testVerifier) ExistsOrg(ctx context.Context, orgID string) error {
return nil
}
func (v *testVerifier) VerifierClientID(ctx context.Context, appName string) (string, error) {
return "clientID", nil
func (v *testVerifier) VerifierClientID(ctx context.Context, appName string) (string, string, error) {
return "clientID", "projectID", nil
}
func (v *testVerifier) CheckOrgFeatures(context.Context, string, ...string) error {

View File

@@ -20,8 +20,8 @@ type TokenVerifier struct {
}
type authZRepo interface {
VerifyAccessToken(ctx context.Context, token, verifierClientID string) (userID, agentID, clientID, prefLang, resourceOwner string, err error)
VerifierClientID(ctx context.Context, name string) (clientID string, err error)
VerifyAccessToken(ctx context.Context, token, verifierClientID, projectID string) (userID, agentID, clientID, prefLang, resourceOwner string, err error)
VerifierClientID(ctx context.Context, name string) (clientID, projectID string, err error)
SearchMyMemberships(ctx context.Context) ([]*Membership, error)
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
ExistsOrg(ctx context.Context, orgID string) error
@@ -33,17 +33,18 @@ func Start(authZRepo authZRepo) (v *TokenVerifier) {
}
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID, prefLang, resourceOwner string, err error) {
verifierClientID, err := v.clientIDFromMethod(ctx, method)
verifierClientID, projectID, err := v.clientIDAndProjectIDFromMethod(ctx, method)
if err != nil {
return "", "", "", "", "", err
}
userID, agentID, clientID, prefLang, resourceOwner, err = v.authZRepo.VerifyAccessToken(ctx, token, verifierClientID)
userID, agentID, clientID, prefLang, resourceOwner, err = v.authZRepo.VerifyAccessToken(ctx, token, verifierClientID, projectID)
return userID, clientID, agentID, prefLang, resourceOwner, err
}
type client struct {
id string
name string
id string
projectID string
name string
}
func (v *TokenVerifier) RegisterServer(appName, methodPrefix string, mappings MethodMapping) {
@@ -64,28 +65,28 @@ func prefixFromMethod(method string) (string, bool) {
return parts[1], true
}
func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) (_ string, err error) {
func (v *TokenVerifier) clientIDAndProjectIDFromMethod(ctx context.Context, method string) (clientID, projectID string, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
prefix, ok := prefixFromMethod(method)
if !ok {
return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-GRD2Q", "Errors.Internal")
return "", "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-GRD2Q", "Errors.Internal")
}
app, ok := v.clients.Load(prefix)
if !ok {
return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-G2qrh", "Errors.Internal")
return "", "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-G2qrh", "Errors.Internal")
}
c := app.(*client)
if c.id != "" {
return c.id, nil
return c.id, c.projectID, nil
}
c.id, err = v.authZRepo.VerifierClientID(ctx, c.name)
c.id, c.projectID, err = v.authZRepo.VerifierClientID(ctx, c.name)
if err != nil {
return "", caos_errs.ThrowPermissionDenied(err, "AUTHZ-ptTIF2", "Errors.Internal")
return "", "", caos_errs.ThrowPermissionDenied(err, "AUTHZ-ptTIF2", "Errors.Internal")
}
v.clients.Store(prefix, c)
return c.id, nil
return c.id, c.projectID, nil
}
func (v *TokenVerifier) SearchMyMemberships(ctx context.Context) (_ []*Membership, err error) {
ctx, span := tracing.NewSpan(ctx)

View File

@@ -12,7 +12,7 @@ import (
)
func (s *Server) GetAppByID(ctx context.Context, req *mgmt_pb.GetAppByIDRequest) (*mgmt_pb.GetAppByIDResponse, error) {
app, err := s.project.ApplicationByID(ctx, req.ProjectId, req.AppId)
app, err := s.query.AppByProjectAndAppID(ctx, req.ProjectId, req.AppId)
if err != nil {
return nil, err
}
@@ -26,16 +26,16 @@ func (s *Server) ListApps(ctx context.Context, req *mgmt_pb.ListAppsRequest) (*m
if err != nil {
return nil, err
}
domains, err := s.project.SearchApplications(ctx, queries)
apps, err := s.query.SearchApps(ctx, queries)
if err != nil {
return nil, err
}
return &mgmt_pb.ListAppsResponse{
Result: project_grpc.AppsToPb(domains.Result),
Result: project_grpc.AppsToPb(apps.Apps),
Details: object_grpc.ToListDetails(
domains.TotalResult,
domains.Sequence,
domains.Timestamp,
apps.Count,
apps.Sequence,
apps.Timestamp,
),
}, nil
}
@@ -196,16 +196,16 @@ func (s *Server) ListAppKeys(ctx context.Context, req *mgmt_pb.ListAppKeysReques
if err != nil {
return nil, err
}
domains, err := s.project.SearchClientKeys(ctx, queries)
keys, err := s.project.SearchClientKeys(ctx, queries)
if err != nil {
return nil, err
}
return &mgmt_pb.ListAppKeysResponse{
Result: authn_grpc.KeyViewsToPb(domains.Result),
Result: authn_grpc.KeyViewsToPb(keys.Result),
Details: object_grpc.ToListDetails(
domains.TotalResult,
domains.Sequence,
domains.Timestamp,
keys.TotalResult,
keys.Sequence,
keys.Timestamp,
),
}, nil
}

View File

@@ -9,25 +9,27 @@ import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore/v1/models"
key_model "github.com/caos/zitadel/internal/key/model"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/query"
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
)
func ListAppsRequestToModel(req *mgmt_pb.ListAppsRequest) (*proj_model.ApplicationSearchRequest, error) {
func ListAppsRequestToModel(req *mgmt_pb.ListAppsRequest) (*query.AppSearchQueries, error) {
offset, limit, asc := object.ListQueryToModel(req.Query)
queries, err := app_grpc.AppQueriesToModel(req.Queries)
if err != nil {
return nil, err
}
queries = append(queries, &proj_model.ApplicationSearchQuery{
Key: proj_model.AppSearchKeyProjectID,
Method: domain.SearchMethodEquals,
Value: req.ProjectId,
})
return &proj_model.ApplicationSearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
projectQuery, err := query.NewAppProjectIDSearchQuery(req.ProjectId)
if err != nil {
return nil, err
}
queries = append(queries, projectQuery)
return &query.AppSearchQueries{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
},
//SortingColumn: //TODO: sorting
Queries: queries,
}, nil

View File

@@ -7,11 +7,12 @@ import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/query"
app_pb "github.com/caos/zitadel/pkg/grpc/app"
message_pb "github.com/caos/zitadel/pkg/grpc/message"
)
func AppsToPb(apps []*proj_model.ApplicationView) []*app_pb.App {
func AppsToPb(apps []*query.App) []*app_pb.App {
a := make([]*app_pb.App, len(apps))
for i, app := range apps {
a[i] = AppToPb(app)
@@ -19,7 +20,7 @@ func AppsToPb(apps []*proj_model.ApplicationView) []*app_pb.App {
return a
}
func AppToPb(app *proj_model.ApplicationView) *app_pb.App {
func AppToPb(app *query.App) *app_pb.App {
return &app_pb.App{
Id: app.ID,
Details: object_grpc.ToViewDetailsPb(app.Sequence, app.CreationDate, app.ChangeDate, app.ResourceOwner),
@@ -29,68 +30,68 @@ func AppToPb(app *proj_model.ApplicationView) *app_pb.App {
}
}
func AppConfigToPb(app *proj_model.ApplicationView) app_pb.AppConfig {
if app.IsOIDC {
return AppOIDCConfigToPb(app)
func AppConfigToPb(app *query.App) app_pb.AppConfig {
if app.OIDCConfig != nil {
return AppOIDCConfigToPb(app.OIDCConfig)
}
return AppAPIConfigToPb(app)
return AppAPIConfigToPb(app.APIConfig)
}
func AppOIDCConfigToPb(app *proj_model.ApplicationView) *app_pb.App_OidcConfig {
func AppOIDCConfigToPb(app *query.OIDCApp) *app_pb.App_OidcConfig {
return &app_pb.App_OidcConfig{
OidcConfig: &app_pb.OIDCConfig{
RedirectUris: app.OIDCRedirectUris,
ResponseTypes: OIDCResponseTypesFromModel(app.OIDCResponseTypes),
GrantTypes: OIDCGrantTypesFromModel(app.OIDCGrantTypes),
AppType: OIDCApplicationTypeToPb(domain.OIDCApplicationType(app.OIDCApplicationType)),
ClientId: app.OIDCClientID,
AuthMethodType: OIDCAuthMethodTypeToPb(domain.OIDCAuthMethodType(app.OIDCAuthMethodType)),
PostLogoutRedirectUris: app.OIDCPostLogoutRedirectUris,
Version: OIDCVersionToPb(domain.OIDCVersion(app.OIDCVersion)),
NoneCompliant: app.NoneCompliant,
RedirectUris: app.RedirectURIs,
ResponseTypes: OIDCResponseTypesFromModel(app.ResponseTypes),
GrantTypes: OIDCGrantTypesFromModel(app.GrantTypes),
AppType: OIDCApplicationTypeToPb(app.AppType),
ClientId: app.ClientID,
AuthMethodType: OIDCAuthMethodTypeToPb(app.AuthMethodType),
PostLogoutRedirectUris: app.PostLogoutRedirectURIs,
Version: OIDCVersionToPb(domain.OIDCVersion(app.Version)),
NoneCompliant: len(app.ComplianceProblems) != 0,
ComplianceProblems: ComplianceProblemsToLocalizedMessages(app.ComplianceProblems),
DevMode: app.DevMode,
AccessTokenType: oidcTokenTypeToPb(domain.OIDCTokenType(app.AccessTokenType)),
AccessTokenRoleAssertion: app.AccessTokenRoleAssertion,
IdTokenRoleAssertion: app.IDTokenRoleAssertion,
IdTokenUserinfoAssertion: app.IDTokenUserinfoAssertion,
DevMode: app.IsDevMode,
AccessTokenType: oidcTokenTypeToPb(app.AccessTokenType),
AccessTokenRoleAssertion: app.AssertAccessTokenRole,
IdTokenRoleAssertion: app.AssertIDTokenRole,
IdTokenUserinfoAssertion: app.AssertIDTokenUserinfo,
ClockSkew: durationpb.New(app.ClockSkew),
AdditionalOrigins: app.AdditionalOrigins,
AllowedOrigins: app.OriginAllowList,
AllowedOrigins: app.AllowedOrigins,
},
}
}
func AppAPIConfigToPb(app *proj_model.ApplicationView) app_pb.AppConfig {
func AppAPIConfigToPb(app *query.APIApp) app_pb.AppConfig {
return &app_pb.App_ApiConfig{
ApiConfig: &app_pb.APIConfig{
ClientId: app.OIDCClientID,
ClientId: app.ClientID,
ClientSecret: "", //TODO: remove from proto
AuthMethodType: APIAuthMethodeTypeToPb(domain.APIAuthMethodType(app.OIDCAuthMethodType)),
AuthMethodType: APIAuthMethodeTypeToPb(app.AuthMethodType),
},
}
}
func AppStateToPb(state proj_model.AppState) app_pb.AppState {
func AppStateToPb(state domain.AppState) app_pb.AppState {
switch state {
case proj_model.AppStateActive:
case domain.AppStateActive:
return app_pb.AppState_APP_STATE_ACTIVE
case proj_model.AppStateInactive:
case domain.AppStateInactive:
return app_pb.AppState_APP_STATE_INACTIVE
default:
return app_pb.AppState_APP_STATE_UNSPECIFIED
}
}
func OIDCResponseTypesFromModel(responseTypes []proj_model.OIDCResponseType) []app_pb.OIDCResponseType {
func OIDCResponseTypesFromModel(responseTypes []domain.OIDCResponseType) []app_pb.OIDCResponseType {
oidcResponseTypes := make([]app_pb.OIDCResponseType, len(responseTypes))
for i, responseType := range responseTypes {
switch responseType {
case proj_model.OIDCResponseTypeCode:
case domain.OIDCResponseTypeCode:
oidcResponseTypes[i] = app_pb.OIDCResponseType_OIDC_RESPONSE_TYPE_CODE
case proj_model.OIDCResponseTypeIDToken:
case domain.OIDCResponseTypeIDToken:
oidcResponseTypes[i] = app_pb.OIDCResponseType_OIDC_RESPONSE_TYPE_ID_TOKEN
case proj_model.OIDCResponseTypeIDTokenToken:
case domain.OIDCResponseTypeIDTokenToken:
oidcResponseTypes[i] = app_pb.OIDCResponseType_OIDC_RESPONSE_TYPE_ID_TOKEN_TOKEN
}
}
@@ -98,7 +99,7 @@ func OIDCResponseTypesFromModel(responseTypes []proj_model.OIDCResponseType) []a
}
func OIDCResponseTypesToDomain(responseTypes []app_pb.OIDCResponseType) []domain.OIDCResponseType {
if responseTypes == nil || len(responseTypes) == 0 {
if len(responseTypes) == 0 {
return []domain.OIDCResponseType{domain.OIDCResponseTypeCode}
}
oidcResponseTypes := make([]domain.OIDCResponseType, len(responseTypes))
@@ -115,15 +116,15 @@ func OIDCResponseTypesToDomain(responseTypes []app_pb.OIDCResponseType) []domain
return oidcResponseTypes
}
func OIDCGrantTypesFromModel(grantTypes []proj_model.OIDCGrantType) []app_pb.OIDCGrantType {
func OIDCGrantTypesFromModel(grantTypes []domain.OIDCGrantType) []app_pb.OIDCGrantType {
oidcGrantTypes := make([]app_pb.OIDCGrantType, len(grantTypes))
for i, grantType := range grantTypes {
switch grantType {
case proj_model.OIDCGrantTypeAuthorizationCode:
case domain.OIDCGrantTypeAuthorizationCode:
oidcGrantTypes[i] = app_pb.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE
case proj_model.OIDCGrantTypeImplicit:
case domain.OIDCGrantTypeImplicit:
oidcGrantTypes[i] = app_pb.OIDCGrantType_OIDC_GRANT_TYPE_IMPLICIT
case proj_model.OIDCGrantTypeRefreshToken:
case domain.OIDCGrantTypeRefreshToken:
oidcGrantTypes[i] = app_pb.OIDCGrantType_OIDC_GRANT_TYPE_REFRESH_TOKEN
}
}
@@ -272,8 +273,8 @@ func APIAuthMethodTypeToDomain(authType app_pb.APIAuthMethodType) domain.APIAuth
}
}
func AppQueriesToModel(queries []*app_pb.AppQuery) (_ []*proj_model.ApplicationSearchQuery, err error) {
q := make([]*proj_model.ApplicationSearchQuery, len(queries))
func AppQueriesToModel(queries []*app_pb.AppQuery) (q []query.SearchQuery, err error) {
q = make([]query.SearchQuery, len(queries))
for i, query := range queries {
q[i], err = AppQueryToModel(query)
if err != nil {
@@ -283,10 +284,10 @@ func AppQueriesToModel(queries []*app_pb.AppQuery) (_ []*proj_model.ApplicationS
return q, nil
}
func AppQueryToModel(query *app_pb.AppQuery) (*proj_model.ApplicationSearchQuery, error) {
switch q := query.Query.(type) {
func AppQueryToModel(appQuery *app_pb.AppQuery) (query.SearchQuery, error) {
switch q := appQuery.Query.(type) {
case *app_pb.AppQuery_NameQuery:
return AppQueryNameToModel(q.NameQuery), nil
return query.NewAppNameSearchQuery(object_grpc.TextMethodToQuery(q.NameQuery.Method), q.NameQuery.Name)
default:
return nil, errors.ThrowInvalidArgument(nil, "APP-Add46", "List.Query.Invalid")
}

View File

@@ -21,7 +21,7 @@ var (
type verifierMock struct{}
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, string, string, error) {
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID, projectID string) (string, string, string, string, string, error) {
return "", "", "", "", "", nil
}
func (v *verifierMock) SearchMyMemberships(ctx context.Context) ([]*authz.Membership, error) {
@@ -34,8 +34,8 @@ func (v *verifierMock) ProjectIDAndOriginsByClientID(ctx context.Context, client
func (v *verifierMock) ExistsOrg(ctx context.Context, orgID string) error {
return nil
}
func (v *verifierMock) VerifierClientID(ctx context.Context, appName string) (string, error) {
return "", nil
func (v *verifierMock) VerifierClientID(ctx context.Context, appName string) (string, string, error) {
return "", "", nil
}
func (v *verifierMock) CheckOrgFeatures(context.Context, string, ...string) error {
return nil

View File

@@ -13,7 +13,6 @@ import (
"github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/tracing"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
@@ -26,15 +25,20 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest
if !ok {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id")
}
app, err := o.repo.ApplicationByClientID(ctx, req.ClientID)
projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, req.ClientID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-AEG4d", "Errors.Internal")
}
req.Scopes, err = o.assertProjectRoleScopes(app, req.Scopes)
project, err := o.query.ProjectByID(ctx, projectID)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-w4wIn", "Errors.Internal")
}
req.Scopes, err = o.assertProjectRoleScopes(project, req.Scopes)
if err != nil {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-Gqrfg", "Errors.Internal")
}
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
//TODO: ensure splitting of command and query side durring auth request and login refactoring
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
if err != nil {
return nil, err
@@ -205,8 +209,8 @@ func (o *OPStorage) GetKeySet(ctx context.Context) (_ *jose.JSONWebKeySet, err e
return o.repo.GetKeySet(ctx)
}
func (o *OPStorage) assertProjectRoleScopes(app *proj_model.ApplicationView, scopes []string) ([]string, error) {
if !app.ProjectRoleAssertion {
func (o *OPStorage) assertProjectRoleScopes(project *query.Project, scopes []string) ([]string, error) {
if !project.ProjectRoleAssertion {
return scopes, nil
}
for _, scope := range scopes {
@@ -214,7 +218,7 @@ func (o *OPStorage) assertProjectRoleScopes(app *proj_model.ApplicationView, sco
return scopes, nil
}
}
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(app.ProjectID)
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(project.ID)
if err != nil {
return nil, errors.ThrowInternal(err, "OIDC-Cyc78", "Errors.Internal")
}

View File

@@ -12,11 +12,10 @@ import (
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/auth_request/model"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/query"
"github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model"
@@ -37,11 +36,11 @@ const (
func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (_ op.Client, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
client, err := o.repo.ApplicationByClientID(ctx, id)
client, err := o.query.AppByOIDCClientID(ctx, id)
if err != nil {
return nil, err
}
if client.State != proj_model.AppStateActive {
if client.State != domain.AppStateActive {
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sdaGg", "client is not active")
}
projectIDQuery, err := query.NewProjectRoleProjectIDSearchQuery(client.ProjectID)
@@ -125,11 +124,11 @@ func (o *OPStorage) SetUserinfoFromToken(ctx context.Context, userInfo oidc.User
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
if token.ApplicationID != "" {
app, err := o.repo.ApplicationByClientID(ctx, token.ApplicationID)
app, err := o.query.AppByOIDCClientID(ctx, token.ApplicationID)
if err != nil {
return err
}
if origin != "" && !http.IsOriginAllowed(app.OriginAllowList, origin) {
if origin != "" && !http.IsOriginAllowed(app.OIDCConfig.AllowedOrigins, origin) {
return errors.ThrowPermissionDenied(nil, "OIDC-da1f3", "origin is not allowed")
}
}
@@ -202,8 +201,8 @@ func (o *OPStorage) SetUserinfoFromScopes(ctx context.Context, userInfo oidc.Use
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
}
if strings.HasPrefix(scope, model.OrgDomainPrimaryScope) {
userInfo.AppendClaims(model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, model.OrgDomainPrimaryScope))
if strings.HasPrefix(scope, authreq_model.OrgDomainPrimaryScope) {
userInfo.AppendClaims(authreq_model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, authreq_model.OrgDomainPrimaryScope))
}
}
}
@@ -225,12 +224,12 @@ func (o *OPStorage) SetIntrospectionFromToken(ctx context.Context, introspection
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Dsfb2", "token is not valid or has expired")
}
app, err := o.repo.ApplicationByClientID(ctx, clientID)
projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, clientID)
if err != nil {
return errors.ThrowPermissionDenied(nil, "OIDC-Adfg5", "client not found")
}
for _, aud := range token.Audience {
if aud == clientID || aud == app.ProjectID {
if aud == clientID || aud == projectID {
err := o.SetUserinfoFromScopes(ctx, introspection, token.UserID, clientID, token.Scopes)
if err != nil {
return err
@@ -266,8 +265,8 @@ func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie
}
if strings.HasPrefix(scope, ScopeProjectRolePrefix) {
roles = append(roles, strings.TrimPrefix(scope, ScopeProjectRolePrefix))
} else if strings.HasPrefix(scope, model.OrgDomainPrimaryScope) {
claims = appendClaim(claims, model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, model.OrgDomainPrimaryScope))
} else if strings.HasPrefix(scope, authreq_model.OrgDomainPrimaryScope) {
claims = appendClaim(claims, authreq_model.OrgDomainPrimaryClaim, strings.TrimPrefix(scope, authreq_model.OrgDomainPrimaryScope))
}
}
if len(roles) == 0 || clientID == "" {
@@ -284,11 +283,11 @@ func (o *OPStorage) GetPrivateClaimsFromScopes(ctx context.Context, userID, clie
}
func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID string, requestedRoles []string) (map[string]map[string]string, error) {
app, err := o.repo.ApplicationByClientID(ctx, applicationID)
projectID, err := o.query.ProjectIDFromOIDCClientID(ctx, applicationID)
if err != nil {
return nil, err
}
grants, err := o.repo.UserGrantsByProjectAndUserID(app.ProjectID, userID)
grants, err := o.repo.UserGrantsByProjectAndUserID(projectID, userID)
if err != nil {
return nil, err
}

View File

@@ -8,24 +8,25 @@ import (
"github.com/caos/oidc/pkg/op"
authreq_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/query"
)
type Client struct {
*model.ApplicationView
app *query.App
defaultLoginURL string
defaultAccessTokenLifetime time.Duration
defaultIdTokenLifetime time.Duration
allowedScopes []string
}
func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration, allowedScopes []string) (op.Client, error) {
if !app.IsOIDC {
func ClientFromBusiness(app *query.App, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration, allowedScopes []string) (op.Client, error) {
if app.OIDCConfig == nil {
return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application")
}
return &Client{
ApplicationView: app,
app: app,
defaultLoginURL: defaultLoginURL,
defaultAccessTokenLifetime: defaultAccessTokenLifetime,
defaultIdTokenLifetime: defaultIdTokenLifetime,
@@ -34,15 +35,15 @@ func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defa
}
func (c *Client) ApplicationType() op.ApplicationType {
return op.ApplicationType(c.OIDCApplicationType)
return op.ApplicationType(c.app.OIDCConfig.AppType)
}
func (c *Client) AuthMethod() oidc.AuthMethod {
return authMethodToOIDC(c.OIDCAuthMethodType)
return authMethodToOIDC(c.app.OIDCConfig.AuthMethodType)
}
func (c *Client) GetID() string {
return c.OIDCClientID
return c.app.OIDCConfig.ClientID
}
func (c *Client) LoginURL(id string) string {
@@ -50,28 +51,28 @@ func (c *Client) LoginURL(id string) string {
}
func (c *Client) RedirectURIs() []string {
return c.OIDCRedirectUris
return c.app.OIDCConfig.RedirectURIs
}
func (c *Client) PostLogoutRedirectURIs() []string {
return c.OIDCPostLogoutRedirectUris
return c.app.OIDCConfig.PostLogoutRedirectURIs
}
func (c *Client) ResponseTypes() []oidc.ResponseType {
return responseTypesToOIDC(c.OIDCResponseTypes)
return responseTypesToOIDC(c.app.OIDCConfig.ResponseTypes)
}
func (c *Client) GrantTypes() []oidc.GrantType {
return grantTypesToOIDC(c.OIDCGrantTypes)
return grantTypesToOIDC(c.app.OIDCConfig.GrantTypes)
}
func (c *Client) DevMode() bool {
return c.ApplicationView.DevMode
return c.app.OIDCConfig.IsDevMode
}
func (c *Client) RestrictAdditionalIdTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
if c.IDTokenRoleAssertion {
if c.app.OIDCConfig.AssertIDTokenRole {
return scopes
}
return removeScopeWithPrefix(scopes, ScopeProjectRolePrefix)
@@ -80,7 +81,7 @@ func (c *Client) RestrictAdditionalIdTokenScopes() func(scopes []string) []strin
func (c *Client) RestrictAdditionalAccessTokenScopes() func(scopes []string) []string {
return func(scopes []string) []string {
if c.AccessTokenRoleAssertion {
if c.app.OIDCConfig.AssertAccessTokenRole {
return scopes
}
return removeScopeWithPrefix(scopes, ScopeProjectRolePrefix)
@@ -96,7 +97,7 @@ func (c *Client) IDTokenLifetime() time.Duration {
}
func (c *Client) AccessTokenType() op.AccessTokenType {
return accessTokenTypeToOIDC(c.ApplicationView.AccessTokenType)
return accessTokenTypeToOIDC(c.app.OIDCConfig.AccessTokenType)
}
func (c *Client) IsScopeAllowed(scope string) bool {
@@ -124,40 +125,40 @@ func (c *Client) IsScopeAllowed(scope string) bool {
}
func (c *Client) ClockSkew() time.Duration {
return c.ApplicationView.ClockSkew
return c.app.OIDCConfig.ClockSkew
}
func (c *Client) IDTokenUserinfoClaimsAssertion() bool {
return c.ApplicationView.IDTokenUserinfoAssertion
return c.app.OIDCConfig.AssertIDTokenUserinfo
}
func accessTokenTypeToOIDC(tokenType model.OIDCTokenType) op.AccessTokenType {
func accessTokenTypeToOIDC(tokenType domain.OIDCTokenType) op.AccessTokenType {
switch tokenType {
case model.OIDCTokenTypeBearer:
case domain.OIDCTokenTypeBearer:
return op.AccessTokenTypeBearer
case model.OIDCTokenTypeJWT:
case domain.OIDCTokenTypeJWT:
return op.AccessTokenTypeJWT
default:
return op.AccessTokenTypeBearer
}
}
func authMethodToOIDC(authType model.OIDCAuthMethodType) oidc.AuthMethod {
func authMethodToOIDC(authType domain.OIDCAuthMethodType) oidc.AuthMethod {
switch authType {
case model.OIDCAuthMethodTypeBasic:
case domain.OIDCAuthMethodTypeBasic:
return oidc.AuthMethodBasic
case model.OIDCAuthMethodTypePost:
case domain.OIDCAuthMethodTypePost:
return oidc.AuthMethodPost
case model.OIDCAuthMethodTypeNone:
case domain.OIDCAuthMethodTypeNone:
return oidc.AuthMethodNone
case model.OIDCAuthMethodTypePrivateKeyJWT:
case domain.OIDCAuthMethodTypePrivateKeyJWT:
return oidc.AuthMethodPrivateKeyJWT
default:
return oidc.AuthMethodBasic
}
}
func responseTypesToOIDC(responseTypes []model.OIDCResponseType) []oidc.ResponseType {
func responseTypesToOIDC(responseTypes []domain.OIDCResponseType) []oidc.ResponseType {
oidcTypes := make([]oidc.ResponseType, len(responseTypes))
for i, t := range responseTypes {
oidcTypes[i] = responseTypeToOIDC(t)
@@ -165,20 +166,20 @@ func responseTypesToOIDC(responseTypes []model.OIDCResponseType) []oidc.Response
return oidcTypes
}
func responseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType {
func responseTypeToOIDC(responseType domain.OIDCResponseType) oidc.ResponseType {
switch responseType {
case model.OIDCResponseTypeCode:
case domain.OIDCResponseTypeCode:
return oidc.ResponseTypeCode
case model.OIDCResponseTypeIDTokenToken:
case domain.OIDCResponseTypeIDTokenToken:
return oidc.ResponseTypeIDToken
case model.OIDCResponseTypeIDToken:
case domain.OIDCResponseTypeIDToken:
return oidc.ResponseTypeIDTokenOnly
default:
return oidc.ResponseTypeCode
}
}
func grantTypesToOIDC(grantTypes []model.OIDCGrantType) []oidc.GrantType {
func grantTypesToOIDC(grantTypes []domain.OIDCGrantType) []oidc.GrantType {
oidcTypes := make([]oidc.GrantType, len(grantTypes))
for i, t := range grantTypes {
oidcTypes[i] = grantTypeToOIDC(t)
@@ -186,13 +187,13 @@ func grantTypesToOIDC(grantTypes []model.OIDCGrantType) []oidc.GrantType {
return oidcTypes
}
func grantTypeToOIDC(grantType model.OIDCGrantType) oidc.GrantType {
func grantTypeToOIDC(grantType domain.OIDCGrantType) oidc.GrantType {
switch grantType {
case model.OIDCGrantTypeAuthorizationCode:
case domain.OIDCGrantTypeAuthorizationCode:
return oidc.GrantTypeCode
case model.OIDCGrantTypeImplicit:
case domain.OIDCGrantTypeImplicit:
return oidc.GrantTypeImplicit
case model.OIDCGrantTypeRefreshToken:
case domain.OIDCGrantTypeRefreshToken:
return oidc.GrantTypeRefreshToken
default:
return oidc.GrantTypeCode