2020-06-05 05:50:04 +00:00
package oidc
import (
"context"
2023-07-10 13:27:00 +00:00
"encoding/base64"
2020-10-16 05:49:38 +00:00
"strings"
2020-06-05 05:50:04 +00:00
"time"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/logging"
2023-10-17 15:19:51 +00:00
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
2020-06-05 05:50:04 +00:00
2023-10-25 12:09:15 +00:00
"github.com/zitadel/zitadel/internal/activity"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/api/authz"
2023-07-10 13:27:00 +00:00
http_utils "github.com/zitadel/zitadel/internal/api/http"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/api/http/middleware"
2023-07-10 13:27:00 +00:00
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/user/model"
2023-12-08 14:30:55 +00:00
"github.com/zitadel/zitadel/internal/zerrors"
2020-06-05 05:50:04 +00:00
)
2023-07-10 13:27:00 +00:00
const (
LoginClientHeader = "x-zitadel-login-client"
)
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) CreateAuthRequest ( ctx context . Context , req * oidc . AuthRequest , userID string ) ( _ op . AuthRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-10 13:27:00 +00:00
headers , _ := http_utils . HeadersFromCtx ( ctx )
if loginClient := headers . Get ( LoginClientHeader ) ; loginClient != "" {
return o . createAuthRequestLoginClient ( ctx , req , userID , loginClient )
}
return o . createAuthRequest ( ctx , req , userID )
}
func ( o * OPStorage ) createAuthRequestLoginClient ( ctx context . Context , req * oidc . AuthRequest , hintUserID , loginClient string ) ( op . AuthRequest , error ) {
2023-11-20 15:21:08 +00:00
project , err := o . query . ProjectByClientID ( ctx , req . ClientID )
2023-07-10 13:27:00 +00:00
if err != nil {
return nil , err
}
scope , err := o . assertProjectRoleScopesByProject ( ctx , project , req . Scopes )
if err != nil {
return nil , err
}
audience , err := o . audienceFromProjectID ( ctx , project . ID )
if err != nil {
return nil , err
}
audience = domain . AddAudScopeToAudience ( ctx , audience , scope )
authRequest := & command . AuthRequest {
LoginClient : loginClient ,
ClientID : req . ClientID ,
RedirectURI : req . RedirectURI ,
State : req . State ,
Nonce : req . Nonce ,
Scope : scope ,
Audience : audience ,
ResponseType : ResponseTypeToBusiness ( req . ResponseType ) ,
CodeChallenge : CodeChallengeToBusiness ( req . CodeChallenge , req . CodeChallengeMethod ) ,
Prompt : PromptToBusiness ( req . Prompt ) ,
UILocales : UILocalesToBusiness ( req . UILocales ) ,
MaxAge : MaxAgeToBusiness ( req . MaxAge ) ,
}
if req . LoginHint != "" {
authRequest . LoginHint = & req . LoginHint
}
if hintUserID != "" {
authRequest . HintUserID = & hintUserID
}
aar , err := o . command . AddAuthRequest ( ctx , authRequest )
if err != nil {
return nil , err
}
return & AuthRequestV2 { aar } , nil
}
func ( o * OPStorage ) createAuthRequest ( ctx context . Context , req * oidc . AuthRequest , userID string ) ( _ op . AuthRequest , err error ) {
2020-08-31 06:49:35 +00:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
2020-06-05 05:50:04 +00:00
if ! ok {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowPreconditionFailed ( nil , "OIDC-sd436" , "no user agent id" )
2020-06-05 05:50:04 +00:00
}
2021-12-17 15:11:18 +00:00
req . Scopes , err = o . assertProjectRoleScopes ( ctx , req . ClientID , req . Scopes )
2020-10-16 05:49:38 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowPreconditionFailed ( err , "OIDC-Gqrfg" , "Errors.Internal" )
2020-10-16 05:49:38 +00:00
}
2020-06-05 05:50:04 +00:00
authRequest := CreateAuthRequestToBusiness ( ctx , req , userAgentID , userID )
resp , err := o . repo . CreateAuthRequest ( ctx , authRequest )
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2023-07-10 13:27:00 +00:00
func ( o * OPStorage ) audienceFromProjectID ( ctx context . Context , projectID string ) ( [ ] string , error ) {
projectIDQuery , err := query . NewAppProjectIDSearchQuery ( projectID )
if err != nil {
return nil , err
}
2023-11-21 12:11:38 +00:00
appIDs , err := o . query . SearchClientIDs ( ctx , & query . AppSearchQueries { Queries : [ ] query . SearchQuery { projectIDQuery } } )
2023-07-10 13:27:00 +00:00
if err != nil {
return nil , err
}
return append ( appIDs , projectID ) , nil
}
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) AuthRequestByID ( ctx context . Context , id string ) ( _ op . AuthRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-10 13:27:00 +00:00
if strings . HasPrefix ( id , command . IDPrefixV2 ) {
req , err := o . command . GetCurrentAuthRequest ( ctx , id )
if err != nil {
return nil , err
}
return & AuthRequestV2 { req } , nil
}
2020-08-31 06:49:35 +00:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
if ! ok {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowPreconditionFailed ( nil , "OIDC-D3g21" , "no user agent id" )
2020-08-31 06:49:35 +00:00
}
2022-04-05 05:58:09 +00:00
resp , err := o . repo . AuthRequestByIDCheckLoggedIn ( ctx , id , userAgentID )
2020-06-05 05:50:04 +00:00
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) AuthRequestByCode ( ctx context . Context , code string ) ( _ op . AuthRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2022-03-23 08:02:39 +00:00
2023-07-10 13:27:00 +00:00
plainCode , err := o . decryptGrant ( code )
if err != nil {
return nil , err
}
if strings . HasPrefix ( plainCode , command . IDPrefixV2 ) {
authReq , err := o . command . ExchangeAuthCode ( ctx , plainCode )
if err != nil {
return nil , err
}
return & AuthRequestV2 { authReq } , nil
}
2022-04-05 05:58:09 +00:00
resp , err := o . repo . AuthRequestByCode ( ctx , code )
2020-06-05 05:50:04 +00:00
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2023-07-10 13:27:00 +00:00
// decryptGrant decrypts a code or refresh_token
func ( o * OPStorage ) decryptGrant ( grant string ) ( string , error ) {
decodedGrant , err := base64 . RawURLEncoding . DecodeString ( grant )
if err != nil {
return "" , err
}
return o . encAlg . DecryptString ( decodedGrant , o . encAlg . EncryptionKeyID ( ) )
}
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) SaveAuthCode ( ctx context . Context , id , code string ) ( err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-10 13:27:00 +00:00
if strings . HasPrefix ( id , command . IDPrefixV2 ) {
return o . command . AddAuthRequestCode ( ctx , id , code )
}
2020-08-31 06:49:35 +00:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
if ! ok {
2023-12-08 14:30:55 +00:00
return zerrors . ThrowPreconditionFailed ( nil , "OIDC-Dgus2" , "no user agent id" )
2020-08-31 06:49:35 +00:00
}
2022-04-05 05:58:09 +00:00
return o . repo . SaveAuthCode ( ctx , id , code , userAgentID )
2020-06-05 05:50:04 +00:00
}
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) DeleteAuthRequest ( ctx context . Context , id string ) ( err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2022-03-23 08:02:39 +00:00
2022-04-05 05:58:09 +00:00
return o . repo . DeleteAuthRequest ( ctx , id )
2020-06-05 05:50:04 +00:00
}
2021-05-20 11:33:35 +00:00
func ( o * OPStorage ) CreateAccessToken ( ctx context . Context , req op . TokenRequest ) ( _ string , _ time . Time , err error ) {
2020-10-21 08:18:34 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-10 13:27:00 +00:00
2021-03-29 12:50:58 +00:00
var userAgentID , applicationID , userOrgID string
2023-07-10 13:27:00 +00:00
switch authReq := req . ( type ) {
case * AuthRequest :
2020-09-17 06:49:33 +00:00
userAgentID = authReq . AgentID
applicationID = authReq . ApplicationID
2021-03-29 12:50:58 +00:00
userOrgID = authReq . UserOrgID
2023-07-10 13:27:00 +00:00
case * AuthRequestV2 :
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , "" , authReq . CurrentAuthRequest . UserID , activity . OIDCAccessToken )
2023-07-10 13:27:00 +00:00
return o . command . AddOIDCSessionAccessToken ( setContextUserSystem ( ctx ) , authReq . GetID ( ) )
2020-07-09 12:05:12 +00:00
}
2022-09-27 10:53:49 +00:00
accessTokenLifetime , _ , _ , _ , err := o . getOIDCSettings ( ctx )
if err != nil {
return "" , time . Time { } , err
}
resp , err := o . command . AddUserToken ( setContextUserSystem ( ctx ) , userOrgID , userAgentID , applicationID , req . GetSubject ( ) , req . GetAudience ( ) , req . GetScopes ( ) , accessTokenLifetime ) //PLANNED: lifetime from client
2020-06-05 05:50:04 +00:00
if err != nil {
return "" , time . Time { } , err
}
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , userOrgID , req . GetSubject ( ) , activity . OIDCAccessToken )
2020-10-15 11:52:41 +00:00
return resp . TokenID , resp . Expiration , nil
2020-06-05 05:50:04 +00:00
}
2021-05-20 11:33:35 +00:00
func ( o * OPStorage ) CreateAccessAndRefreshTokens ( ctx context . Context , req op . TokenRequest , refreshToken string ) ( _ , _ string , _ time . Time , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-10 13:27:00 +00:00
// handle V2 request directly
switch tokenReq := req . ( type ) {
case * AuthRequestV2 :
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , "" , tokenReq . GetSubject ( ) , activity . OIDCRefreshToken )
2023-07-10 13:27:00 +00:00
return o . command . AddOIDCSessionRefreshAndAccessToken ( setContextUserSystem ( ctx ) , tokenReq . GetID ( ) )
case * RefreshTokenRequestV2 :
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , "" , tokenReq . GetSubject ( ) , activity . OIDCRefreshToken )
2023-07-10 13:27:00 +00:00
return o . command . ExchangeOIDCSessionRefreshAndAccessToken ( setContextUserSystem ( ctx ) , tokenReq . OIDCSessionWriteModel . AggregateID , refreshToken , tokenReq . RequestedScopes )
}
2021-05-26 07:01:07 +00:00
userAgentID , applicationID , userOrgID , authTime , authMethodsReferences := getInfoFromRequest ( req )
2021-12-17 15:11:18 +00:00
scopes , err := o . assertProjectRoleScopes ( ctx , applicationID , req . GetScopes ( ) )
if err != nil {
2023-12-08 14:30:55 +00:00
return "" , "" , time . Time { } , zerrors . ThrowPreconditionFailed ( err , "OIDC-Df2fq" , "Errors.Internal" )
2021-12-17 15:11:18 +00:00
}
if request , ok := req . ( op . RefreshTokenRequest ) ; ok {
request . SetCurrentScopes ( scopes )
}
2022-09-27 10:53:49 +00:00
accessTokenLifetime , _ , refreshTokenIdleExpiration , refreshTokenExpiration , err := o . getOIDCSettings ( ctx )
if err != nil {
return "" , "" , time . Time { } , err
}
2022-03-24 13:00:24 +00:00
resp , token , err := o . command . AddAccessAndRefreshToken ( setContextUserSystem ( ctx ) , userOrgID , userAgentID , applicationID , req . GetSubject ( ) ,
2022-09-27 10:53:49 +00:00
refreshToken , req . GetAudience ( ) , scopes , authMethodsReferences , accessTokenLifetime ,
refreshTokenIdleExpiration , refreshTokenExpiration , authTime ) //PLANNED: lifetime from client
2021-05-20 11:33:35 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
if zerrors . IsErrorInvalidArgument ( err ) {
2021-11-03 07:35:24 +00:00
err = oidc . ErrInvalidGrant ( ) . WithParent ( err )
}
2021-05-20 11:33:35 +00:00
return "" , "" , time . Time { } , err
}
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , userOrgID , req . GetSubject ( ) , activity . OIDCRefreshToken )
2021-05-20 11:33:35 +00:00
return resp . TokenID , token , resp . Expiration , nil
}
2021-05-26 07:01:07 +00:00
func getInfoFromRequest ( req op . TokenRequest ) ( string , string , string , time . Time , [ ] string ) {
authReq , ok := req . ( * AuthRequest )
if ok {
return authReq . AgentID , authReq . ApplicationID , authReq . UserOrgID , authReq . AuthTime , authReq . GetAMR ( )
}
refreshReq , ok := req . ( * RefreshTokenRequest )
if ok {
return refreshReq . UserAgentID , refreshReq . ClientID , "" , refreshReq . AuthTime , refreshReq . AuthMethodsReferences
}
return "" , "" , "" , time . Time { } , nil
}
2023-07-10 13:27:00 +00:00
func ( o * OPStorage ) TokenRequestByRefreshToken ( ctx context . Context , refreshToken string ) ( _ op . RefreshTokenRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-17 12:33:37 +00:00
plainToken , err := o . decryptGrant ( refreshToken )
2023-07-10 13:27:00 +00:00
if err != nil {
return nil , err
}
2023-07-17 12:33:37 +00:00
if strings . HasPrefix ( plainToken , command . IDPrefixV2 ) {
oidcSession , err := o . command . OIDCSessionByRefreshToken ( ctx , plainToken )
2023-07-10 13:27:00 +00:00
if err != nil {
return nil , err
}
2023-10-25 12:09:15 +00:00
// trigger activity log for authentication for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , "" , oidcSession . UserID , activity . OIDCRefreshToken )
2023-07-10 13:27:00 +00:00
return & RefreshTokenRequestV2 { OIDCSessionWriteModel : oidcSession } , nil
}
2023-03-28 11:28:56 +00:00
tokenView , err := o . repo . RefreshTokenByToken ( ctx , refreshToken )
2021-05-20 11:33:35 +00:00
if err != nil {
return nil , err
}
2023-10-25 12:09:15 +00:00
// trigger activity log for use of refresh token for user
2023-11-28 15:56:29 +00:00
activity . Trigger ( ctx , tokenView . ResourceOwner , tokenView . UserID , activity . OIDCRefreshToken )
2021-05-20 11:33:35 +00:00
return RefreshTokenRequestFromBusiness ( tokenView ) , nil
}
2020-10-21 08:18:34 +00:00
func ( o * OPStorage ) TerminateSession ( ctx context . Context , userID , clientID string ) ( err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-08-31 06:49:35 +00:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
2020-06-05 05:50:04 +00:00
if ! ok {
2022-07-27 07:49:16 +00:00
logging . Error ( "no user agent id" )
2023-12-08 14:30:55 +00:00
return zerrors . ThrowPreconditionFailed ( nil , "OIDC-fso7F" , "no user agent id" )
2020-06-05 05:50:04 +00:00
}
2021-02-08 10:30:30 +00:00
userIDs , err := o . repo . UserSessionUserIDsByAgentID ( ctx , userAgentID )
if err != nil {
2022-07-27 07:49:16 +00:00
logging . WithError ( err ) . Error ( "error retrieving user sessions" )
2021-02-08 10:30:30 +00:00
return err
}
2021-07-19 13:12:00 +00:00
if len ( userIDs ) == 0 {
return nil
}
2022-03-24 13:00:24 +00:00
data := authz . CtxData {
UserID : userID ,
}
err = o . command . HumansSignOut ( authz . SetCtxData ( ctx , data ) , userAgentID , userIDs )
2022-07-27 07:49:16 +00:00
logging . OnError ( err ) . Error ( "error signing out" )
2021-07-08 11:55:21 +00:00
return err
2020-06-05 05:50:04 +00:00
}
2023-07-19 11:17:39 +00:00
func ( o * OPStorage ) TerminateSessionFromRequest ( ctx context . Context , endSessionRequest * op . EndSessionRequest ) ( redirectURI string , err error ) {
2023-07-17 12:33:37 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-07-19 11:17:39 +00:00
// check for the login client header
// and if not provided, terminate the session using the V1 method
headers , _ := http_utils . HeadersFromCtx ( ctx )
if loginClient := headers . Get ( LoginClientHeader ) ; loginClient == "" {
return endSessionRequest . RedirectURI , o . TerminateSession ( ctx , endSessionRequest . UserID , endSessionRequest . ClientID )
}
// in case there are not id_token_hint, redirect to the UI and let it decide which session to terminate
if endSessionRequest . IDTokenHintClaims == nil {
return o . defaultLogoutURLV2 + endSessionRequest . RedirectURI , nil
}
// terminate the session of the id_token_hint
_ , err = o . command . TerminateSessionWithoutTokenCheck ( ctx , endSessionRequest . IDTokenHintClaims . SessionID )
if err != nil {
return "" , err
}
return endSessionRequest . RedirectURI , nil
}
func ( o * OPStorage ) RevokeToken ( ctx context . Context , token , userID , clientID string ) ( err * oidc . Error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) {
// check for nil, because `err` is not an error and EndWithError would panic
if err == nil {
span . End ( )
return
}
span . EndWithError ( err )
} ( )
2023-07-17 12:33:37 +00:00
if strings . HasPrefix ( token , command . IDPrefixV2 ) {
err := o . command . RevokeOIDCSessionToken ( ctx , token , clientID )
if err == nil {
return nil
}
2023-12-08 14:30:55 +00:00
if zerrors . IsPreconditionFailed ( err ) {
2023-07-17 12:33:37 +00:00
return oidc . ErrInvalidClient ( ) . WithDescription ( "token was not issued for this client" )
}
return oidc . ErrServerError ( ) . WithParent ( err )
}
return o . revokeTokenV1 ( ctx , token , userID , clientID )
}
func ( o * OPStorage ) revokeTokenV1 ( ctx context . Context , token , userID , clientID string ) * oidc . Error {
2023-03-28 11:28:56 +00:00
refreshToken , err := o . repo . RefreshTokenByID ( ctx , token , userID )
2021-11-03 07:35:24 +00:00
if err == nil {
if refreshToken . ClientID != clientID {
return oidc . ErrInvalidClient ( ) . WithDescription ( "token was not issued for this client" )
}
_ , err = o . command . RevokeRefreshToken ( ctx , refreshToken . UserID , refreshToken . ResourceOwner , refreshToken . ID )
2023-12-08 14:30:55 +00:00
if err == nil || zerrors . IsNotFound ( err ) {
2021-11-03 07:35:24 +00:00
return nil
}
return oidc . ErrServerError ( ) . WithParent ( err )
}
2022-09-15 12:59:40 +00:00
accessToken , err := o . repo . TokenByIDs ( ctx , userID , token )
2021-11-03 07:35:24 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
if zerrors . IsNotFound ( err ) {
2021-11-03 07:35:24 +00:00
return nil
}
return oidc . ErrServerError ( ) . WithParent ( err )
}
if accessToken . ApplicationID != clientID {
return oidc . ErrInvalidClient ( ) . WithDescription ( "token was not issued for this client" )
}
_ , err = o . command . RevokeAccessToken ( ctx , userID , accessToken . ResourceOwner , accessToken . ID )
2023-12-08 14:30:55 +00:00
if err == nil || zerrors . IsNotFound ( err ) {
2021-11-03 07:35:24 +00:00
return nil
}
return oidc . ErrServerError ( ) . WithParent ( err )
}
2023-03-28 11:28:56 +00:00
func ( o * OPStorage ) GetRefreshTokenInfo ( ctx context . Context , clientID string , token string ) ( userID string , tokenID string , err error ) {
2023-07-17 12:33:37 +00:00
plainToken , err := o . decryptGrant ( token )
if err != nil {
return "" , "" , op . ErrInvalidRefreshToken
}
if strings . HasPrefix ( plainToken , command . IDPrefixV2 ) {
oidcSession , err := o . command . OIDCSessionByRefreshToken ( ctx , plainToken )
if err != nil {
return "" , "" , op . ErrInvalidRefreshToken
}
return oidcSession . UserID , oidcSession . OIDCRefreshTokenID ( oidcSession . RefreshTokenID ) , nil
}
2023-03-28 11:28:56 +00:00
refreshToken , err := o . repo . RefreshTokenByToken ( ctx , token )
if err != nil {
return "" , "" , op . ErrInvalidRefreshToken
}
if refreshToken . ClientID != clientID {
return "" , "" , oidc . ErrInvalidClient ( ) . WithDescription ( "token was not issued for this client" )
}
return refreshToken . UserID , refreshToken . ID , nil
}
2021-12-17 15:11:18 +00:00
func ( o * OPStorage ) assertProjectRoleScopes ( ctx context . Context , clientID string , scopes [ ] string ) ( [ ] string , error ) {
2020-10-16 05:49:38 +00:00
for _ , scope := range scopes {
if strings . HasPrefix ( scope , ScopeProjectRolePrefix ) {
return scopes , nil
}
}
2023-11-21 12:11:38 +00:00
projectID , err := o . query . ProjectIDFromOIDCClientID ( ctx , clientID )
2021-12-17 15:11:18 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowPreconditionFailed ( nil , "OIDC-AEG4d" , "Errors.Internal" )
2021-12-17 15:11:18 +00:00
}
2023-11-20 15:21:08 +00:00
project , err := o . query . ProjectByID ( ctx , false , projectID )
2021-12-17 15:11:18 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowPreconditionFailed ( nil , "OIDC-w4wIn" , "Errors.Internal" )
2021-12-17 15:11:18 +00:00
}
if ! project . ProjectRoleAssertion {
return scopes , nil
}
2021-11-26 06:57:05 +00:00
projectIDQuery , err := query . NewProjectRoleProjectIDSearchQuery ( project . ID )
2021-11-04 12:46:15 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowInternal ( err , "OIDC-Cyc78" , "Errors.Internal" )
2021-11-04 12:46:15 +00:00
}
2023-11-20 15:21:08 +00:00
roles , err := o . query . SearchProjectRoles ( ctx , true , & query . ProjectRoleSearchQueries { Queries : [ ] query . SearchQuery { projectIDQuery } } )
2020-10-16 05:49:38 +00:00
if err != nil {
return nil , err
}
2021-11-04 12:46:15 +00:00
for _ , role := range roles . ProjectRoles {
2020-10-16 05:49:38 +00:00
scopes = append ( scopes , ScopeProjectRolePrefix + role . Key )
}
return scopes , nil
}
2022-02-08 08:37:28 +00:00
2023-07-10 13:27:00 +00:00
func ( o * OPStorage ) assertProjectRoleScopesByProject ( ctx context . Context , project * query . Project , scopes [ ] string ) ( [ ] string , error ) {
for _ , scope := range scopes {
if strings . HasPrefix ( scope , ScopeProjectRolePrefix ) {
return scopes , nil
}
}
if ! project . ProjectRoleAssertion {
return scopes , nil
}
projectIDQuery , err := query . NewProjectRoleProjectIDSearchQuery ( project . ID )
if err != nil {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowInternal ( err , "OIDC-Cyc78" , "Errors.Internal" )
2023-07-10 13:27:00 +00:00
}
2023-11-20 15:21:08 +00:00
roles , err := o . query . SearchProjectRoles ( ctx , true , & query . ProjectRoleSearchQueries { Queries : [ ] query . SearchQuery { projectIDQuery } } )
2023-07-10 13:27:00 +00:00
if err != nil {
return nil , err
}
for _ , role := range roles . ProjectRoles {
scopes = append ( scopes , ScopeProjectRolePrefix + role . Key )
}
return scopes , nil
}
2023-04-03 12:26:51 +00:00
func ( o * OPStorage ) assertClientScopesForPAT ( ctx context . Context , token * model . TokenView , clientID , projectID string ) error {
2022-02-08 08:37:28 +00:00
token . Audience = append ( token . Audience , clientID )
projectIDQuery , err := query . NewProjectRoleProjectIDSearchQuery ( projectID )
if err != nil {
2023-12-08 14:30:55 +00:00
return zerrors . ThrowInternal ( err , "OIDC-Cyc78" , "Errors.Internal" )
2022-02-08 08:37:28 +00:00
}
2023-11-20 15:21:08 +00:00
roles , err := o . query . SearchProjectRoles ( ctx , true , & query . ProjectRoleSearchQueries { Queries : [ ] query . SearchQuery { projectIDQuery } } )
2022-02-08 08:37:28 +00:00
if err != nil {
return err
}
for _ , role := range roles . ProjectRoles {
token . Scopes = append ( token . Scopes , ScopeProjectRolePrefix + role . Key )
}
return nil
}
2022-03-24 13:00:24 +00:00
func setContextUserSystem ( ctx context . Context ) context . Context {
data := authz . CtxData {
UserID : "SYSTEM" ,
}
return authz . SetCtxData ( ctx , data )
}
2022-09-27 10:53:49 +00:00
func ( o * OPStorage ) getOIDCSettings ( ctx context . Context ) ( accessTokenLifetime , idTokenLifetime , refreshTokenIdleExpiration , refreshTokenExpiration time . Duration , _ error ) {
oidcSettings , err := o . query . OIDCSettingsByAggID ( ctx , authz . GetInstance ( ctx ) . InstanceID ( ) )
2023-12-08 14:30:55 +00:00
if err != nil && ! zerrors . IsNotFound ( err ) {
2022-09-27 10:53:49 +00:00
return time . Duration ( 0 ) , time . Duration ( 0 ) , time . Duration ( 0 ) , time . Duration ( 0 ) , err
}
if oidcSettings != nil {
return oidcSettings . AccessTokenLifetime , oidcSettings . IdTokenLifetime , oidcSettings . RefreshTokenIdleExpiration , oidcSettings . RefreshTokenExpiration , nil
}
return o . defaultAccessTokenLifetime , o . defaultIdTokenLifetime , o . defaultRefreshTokenIdleExpiration , o . defaultRefreshTokenExpiration , nil
}
2023-07-10 13:27:00 +00:00
func CreateErrorCallbackURL ( authReq op . AuthRequest , reason , description , uri string , authorizer op . Authorizer ) ( string , error ) {
e := struct {
Error string ` schema:"error" `
Description string ` schema:"error_description,omitempty" `
URI string ` schema:"error_uri,omitempty" `
State string ` schema:"state,omitempty" `
} {
Error : reason ,
Description : description ,
URI : uri ,
State : authReq . GetState ( ) ,
}
callback , err := op . AuthResponseURL ( authReq . GetRedirectURI ( ) , authReq . GetResponseType ( ) , authReq . GetResponseMode ( ) , e , authorizer . Encoder ( ) )
if err != nil {
return "" , err
}
return callback , nil
}
func CreateCodeCallbackURL ( ctx context . Context , authReq op . AuthRequest , authorizer op . Authorizer ) ( string , error ) {
code , err := op . CreateAuthRequestCode ( ctx , authReq , authorizer . Storage ( ) , authorizer . Crypto ( ) )
if err != nil {
return "" , err
}
codeResponse := struct {
code string
state string
} {
code : code ,
state : authReq . GetState ( ) ,
}
callback , err := op . AuthResponseURL ( authReq . GetRedirectURI ( ) , authReq . GetResponseType ( ) , authReq . GetResponseMode ( ) , & codeResponse , authorizer . Encoder ( ) )
if err != nil {
return "" , err
}
return callback , err
}
func CreateTokenCallbackURL ( ctx context . Context , req op . AuthRequest , authorizer op . Authorizer ) ( string , error ) {
client , err := authorizer . Storage ( ) . GetClientByClientID ( ctx , req . GetClientID ( ) )
if err != nil {
return "" , err
}
createAccessToken := req . GetResponseType ( ) != oidc . ResponseTypeIDTokenOnly
resp , err := op . CreateTokenResponse ( ctx , req , client , authorizer , createAccessToken , "" , "" )
if err != nil {
return "" , err
}
callback , err := op . AuthResponseURL ( req . GetRedirectURI ( ) , req . GetResponseType ( ) , req . GetResponseMode ( ) , resp , authorizer . Encoder ( ) )
if err != nil {
return "" , err
}
return callback , err
}