2020-06-05 05:50:04 +00:00
package eventstore
import (
"context"
2021-04-06 09:38:39 +00:00
"encoding/base64"
2022-08-23 06:02:36 +00:00
"fmt"
2020-11-20 06:57:39 +00:00
"strings"
"time"
2024-04-15 09:17:36 +00:00
"github.com/go-jose/go-jose/v4"
2024-05-16 05:07:56 +00:00
"github.com/muhlemmer/gu"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/logging"
2023-10-19 10:34:00 +00:00
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/op"
feat: label policy (#1708)
* feat: label policy proto extension
* feat: label policy and activate event
* feat: label policy asset events
* feat: label policy asset commands
* feat: add storage key
* feat: storage key validation
* feat: label policy asset tests
* feat: label policy query side
* feat: avatar
* feat: avatar event
* feat: human avatar
* feat: avatar read side
* feat: font on iam label policy
* feat: label policy font
* feat: possiblity to create bucket on put file
* uplaoder
* login policy logo
* set bucket prefix
* feat: avatar upload
* feat: avatar upload
* feat: use assets on command side
* feat: fix human avatar removed event
* feat: remove human avatar
* feat: mock asset storage
* feat: remove human avatar
* fix(operator): add configuration of asset storage to zitadel operator
* feat(console): private labeling policy (#1697)
* private labeling component, routing, preview
* font, colors, upload, i18n
* show logo
* fix: uniqueness (#1710)
* fix: uniqueconstraint to lower
* feat: change org
* feat: org change test
* feat: change org
* fix: tests
* fix: handle domain claims correctly
* feat: update org
Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
* fix: handle domain claimed event correctly for service users (#1711)
* fix: handle domain claimed event correctly on user view
* fix: ignore domain claimed events for email notifications
* fix: change org
* handle org changed in read models correctly
* fix: change org in user grant handler
Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
* fix: correct value (#1695)
* docs(api): correct link (#1712)
* upload service
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
Co-authored-by: Florian Forster <florian@caos.ch>
* feat: fix tests,
* feat: remove assets from label policy
* fix npm, set environment
* lint ts
* remove stylelinting
* fix(operator): add mapping for console with changed unit tests
* fix(operator): add secrets as env variables to pod
* feat: remove human avatar
* fix(operator): add secrets as env variables to pod
* feat: map label policy
* feat: labelpolicy, admin, mgmt, adv settings (#1715)
* fetch label policy, mgmt, admin service
* feat: advanced beh, links, add, update
* lint ts
* feat: watermark
* feat: remove human avatar
* feat: remove human avatar
* feat: remove human avatar
* feat: remove human avatar
* feat: remove human avatar
* feat: remove human avatar
* feat: remove human avatar
* feat: custom css
* css
* css
* css
* css
* css
* getobject
* feat: dynamic handler
* feat: varibale css
* content info
* css overwrite
* feat: variablen css
* feat: generate css file
* feat: dark mode
* feat: dark mode
* fix logo css
* feat: upload logos
* dark mode with cookie
* feat: handle images in login
* avatar css and begin font
* feat: avatar
* feat: user avatar
* caching of static assets in login
* add avatar.js to main.html
* feat: header dont show logo if no url
* feat: label policy colors
* feat: mock asset storage
* feat: mock asset storage
* feat: fix tests
* feat: user avatar
* feat: header logo
* avatar
* avatar
* make it compatible with go 1.15
* feat: remove unused logos
* fix handler
* fix: styling error handling
* fonts
* fix: download func
* switch to mux
* fix: change upload api to assets
* fix build
* fix: download avatar
* fix: download logos
* fix: my avatar
* font
* fix: remove error msg popup possibility
* fix: docs
* fix: svalidate colors
* rem msg popup from frontend
* fix: email with private labeling
* fix: tests
* fix: email templates
* fix: change migration version
* fix: fix duplicate imports
* fix(console): assets, service url, upload, policy current and preview (#1781)
* upload endpoint, layout
* fetch current, preview, fix upload
* cleanup private labeling
* fix linting
* begin generated asset handler
* generate asset api in dockerfile
* features for label policy
* features for label policy
* features
* flag for asset generator
* change asset generator flag
* fix label policy view in grpc
* fix: layout, activate policy (#1786)
* theme switcher up on top
* change layout
* activate policy
* feat(console): label policy back color, layout (#1788)
* theme switcher up on top
* change layout
* activate policy
* fix overwrite value fc
* reset policy, reset service
* autosave policy, preview desc, layout impv
* layout, i18n
* background colors, inject material styles
* load images
* clean, lint
* fix layout
* set custom hex
* fix content size conversion
* remove font format in generated css
* fix features for assets
* fix(console): label policy colors, image downloads, preview (#1804)
* load images
* colors, images binding
* lint
* refresh emitter
* lint
* propagate font colors
* upload error handling
* label policy feature check
* add blob in csp for console
* log
* fix: feature edits for label policy, refresh state on upload (#1807)
* show error on load image, stop spinner
* fix merge
* fix migration versions
* fix assets
* fix csp
* fix background color
* scss
* fix build
* lint scss
* fix statik for console
* fix features check for label policy
* cleanup
* lint
* public links
* fix notifications
* public links
* feat: merge main
* feat: fix translation files
* fix migration
* set api domain
* fix logo in email
* font face in email
* font face in email
* validate assets on upload
* cleanup
* add missing translations
* add missing translations
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
Co-authored-by: Stefan Benz <stefan@caos.ch>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Florian Forster <florian@caos.ch>
2021-06-04 12:53:51 +00:00
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/api/authz"
2022-08-23 06:02:36 +00:00
http_util "github.com/zitadel/zitadel/internal/api/http"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/authz/repository/eventsourcing/view"
2023-07-14 11:16:16 +00:00
"github.com/zitadel/zitadel/internal/command"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/crypto"
2023-07-14 11:16:16 +00:00
"github.com/zitadel/zitadel/internal/domain"
2023-10-19 10:19:10 +00:00
"github.com/zitadel/zitadel/internal/eventstore"
2022-04-26 23:01:45 +00:00
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
usr_model "github.com/zitadel/zitadel/internal/user/model"
usr_view "github.com/zitadel/zitadel/internal/user/repository/view"
"github.com/zitadel/zitadel/internal/user/repository/view/model"
2023-12-08 14:30:55 +00:00
"github.com/zitadel/zitadel/internal/zerrors"
2020-06-05 05:50:04 +00:00
)
type TokenVerifierRepo struct {
2021-04-06 06:31:18 +00:00
TokenVerificationKey crypto . EncryptionAlgorithm
2023-10-19 10:19:10 +00:00
Eventstore * eventstore . Eventstore
2020-06-05 05:50:04 +00:00
View * view . View
2021-11-21 19:22:25 +00:00
Query * query . Queries
2022-08-23 06:02:36 +00:00
ExternalSecure bool
2020-06-05 05:50:04 +00:00
}
2022-05-25 12:07:16 +00:00
func ( repo * TokenVerifierRepo ) Health ( ) error {
return repo . View . Health ( )
}
2022-05-24 09:18:25 +00:00
func ( repo * TokenVerifierRepo ) tokenByID ( ctx context . Context , tokenID , userID string ) ( _ * usr_model . TokenView , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2022-09-02 14:05:13 +00:00
instanceID := authz . GetInstance ( ctx ) . InstanceID ( )
2023-10-09 07:26:27 +00:00
// always load the latest sequence first, so in case the token was not found by id,
// the sequence will be equal or lower than the actual projection and no events are lost
2023-10-19 10:19:10 +00:00
sequence , err := repo . View . GetLatestState ( ctx )
2023-10-09 07:26:27 +00:00
logging . WithFields ( "instanceID" , instanceID , "userID" , userID , "tokenID" , tokenID ) .
OnError ( err ) .
Errorf ( "could not get current sequence for token check" )
2022-09-15 12:59:40 +00:00
token , viewErr := repo . View . TokenByIDs ( tokenID , userID , instanceID )
2023-12-08 14:30:55 +00:00
if viewErr != nil && ! zerrors . IsNotFound ( viewErr ) {
2020-10-15 11:52:41 +00:00
return nil , viewErr
}
2023-12-08 14:30:55 +00:00
if zerrors . IsNotFound ( viewErr ) {
2020-10-15 11:52:41 +00:00
token = new ( model . TokenView )
token . ID = tokenID
token . UserID = userID
2022-09-02 14:05:13 +00:00
if sequence != nil {
2023-12-14 10:07:47 +00:00
token . ChangeDate = sequence . EventCreatedAt
2022-09-02 14:05:13 +00:00
}
2020-10-15 11:52:41 +00:00
}
2023-12-14 10:07:47 +00:00
events , esErr := repo . getUserEvents ( ctx , userID , instanceID , token . ChangeDate , token . GetRelevantEventTypes ( ) )
2023-12-08 14:30:55 +00:00
if zerrors . IsNotFound ( viewErr ) && len ( events ) == 0 {
return nil , zerrors . ThrowNotFound ( nil , "EVENT-4T90g" , "Errors.Token.NotFound" )
2020-10-15 11:52:41 +00:00
}
if esErr != nil {
2022-08-23 06:02:36 +00:00
logging . WithError ( viewErr ) . WithField ( "traceID" , tracing . TraceIDFromCtx ( ctx ) ) . Debug ( "error retrieving new events" )
2020-10-15 11:52:41 +00:00
return model . TokenViewToModel ( token ) , nil
}
viewToken := * token
for _ , event := range events {
err := token . AppendEventIfMyToken ( event )
if err != nil {
return model . TokenViewToModel ( & viewToken ) , nil
}
}
if ! token . Expiration . After ( time . Now ( ) . UTC ( ) ) || token . Deactivated {
2023-12-08 14:30:55 +00:00
return nil , zerrors . ThrowNotFound ( nil , "EVENT-5Bm9s" , "Errors.Token.NotFound" )
2020-10-15 11:52:41 +00:00
}
return model . TokenViewToModel ( token ) , nil
}
2021-11-26 06:57:05 +00:00
func ( repo * TokenVerifierRepo ) VerifyAccessToken ( ctx context . Context , tokenString , verifierClientID , projectID string ) ( userID string , agentID string , clientID , prefLang , resourceOwner string , err error ) {
2020-10-21 08:18:34 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-10-15 11:52:41 +00:00
2022-08-23 06:02:36 +00:00
tokenID , subject , ok := repo . getTokenIDAndSubject ( ctx , tokenString )
if ! ok {
2023-12-08 14:30:55 +00:00
return "" , "" , "" , "" , "" , zerrors . ThrowUnauthenticated ( nil , "APP-Reb32" , "invalid token" )
2020-10-15 11:52:41 +00:00
}
2023-07-14 11:16:16 +00:00
if strings . HasPrefix ( tokenID , command . IDPrefixV2 ) {
2024-05-16 05:07:56 +00:00
return repo . verifyAccessTokenV2 ( ctx , tokenID , verifierClientID , projectID )
2023-07-14 11:16:16 +00:00
}
if sessionID , ok := strings . CutPrefix ( tokenID , authz . SessionTokenPrefix ) ; ok {
userID , clientID , resourceOwner , err = repo . verifySessionToken ( ctx , sessionID , tokenString )
return
}
return repo . verifyAccessTokenV1 ( ctx , tokenID , subject , verifierClientID , projectID )
}
2024-05-16 05:07:56 +00:00
func ( repo * TokenVerifierRepo ) verifyAccessTokenV1 ( ctx context . Context , tokenID , subject , verifierClientID , projectID string ) ( userID , agentID , clientID , prefLang , resourceOwner string , err error ) {
2023-07-14 11:16:16 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2024-03-28 12:19:03 +00:00
_ , tokenSpan := tracing . NewNamedSpan ( ctx , "tokenByID" )
2022-08-23 06:02:36 +00:00
token , err := repo . tokenByID ( ctx , tokenID , subject )
2022-05-24 09:18:25 +00:00
tokenSpan . EndWithError ( err )
2020-06-05 05:50:04 +00:00
if err != nil {
2023-12-08 14:30:55 +00:00
return "" , "" , "" , "" , "" , zerrors . ThrowUnauthenticated ( err , "APP-BxUSiL" , "invalid token" )
2020-06-05 05:50:04 +00:00
}
2024-03-28 12:19:03 +00:00
if token . Actor != nil {
return "" , "" , "" , "" , "" , zerrors . ThrowPermissionDenied ( nil , "APP-wai8O" , "Errors.TokenExchange.Token.NotForAPI" )
}
2020-06-05 05:50:04 +00:00
if ! token . Expiration . After ( time . Now ( ) . UTC ( ) ) {
2023-12-08 14:30:55 +00:00
return "" , "" , "" , "" , "" , zerrors . ThrowUnauthenticated ( err , "APP-k9KS0" , "invalid token" )
2020-06-05 05:50:04 +00:00
}
2022-02-08 08:37:28 +00:00
if token . IsPAT {
return token . UserID , "" , "" , "" , token . ResourceOwner , nil
}
2023-07-14 11:16:16 +00:00
if err = verifyAudience ( token . Audience , verifierClientID , projectID ) ; err != nil {
return "" , "" , "" , "" , "" , err
}
return token . UserID , token . UserAgentID , token . ApplicationID , token . PreferredLanguage , token . ResourceOwner , nil
}
2024-05-16 05:07:56 +00:00
func ( repo * TokenVerifierRepo ) verifyAccessTokenV2 ( ctx context . Context , token , verifierClientID , projectID string ) ( userID , agentID , clientID , prefLang , resourceOwner string , err error ) {
2023-07-14 11:16:16 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
activeToken , err := repo . Query . ActiveAccessTokenByToken ( ctx , token )
if err != nil {
2024-05-16 05:07:56 +00:00
return "" , "" , "" , "" , "" , err
2023-07-14 11:16:16 +00:00
}
2024-03-20 10:18:46 +00:00
if activeToken . Actor != nil {
2024-05-16 05:07:56 +00:00
return "" , "" , "" , "" , "" , zerrors . ThrowPermissionDenied ( nil , "APP-Shi0J" , "Errors.TokenExchange.Token.NotForAPI" )
2024-03-20 10:18:46 +00:00
}
2023-07-14 11:16:16 +00:00
if err = verifyAudience ( activeToken . Audience , verifierClientID , projectID ) ; err != nil {
2024-05-16 05:07:56 +00:00
return "" , "" , "" , "" , "" , err
2023-07-14 11:16:16 +00:00
}
if err = repo . checkAuthentication ( ctx , activeToken . AuthMethods , activeToken . UserID ) ; err != nil {
2024-05-16 05:07:56 +00:00
return "" , "" , "" , "" , "" , err
2020-06-05 05:50:04 +00:00
}
2024-05-16 05:07:56 +00:00
prefLang = gu . Value ( activeToken . PreferredLanguage ) . String ( )
agentID = gu . Value ( gu . Value ( activeToken . UserAgent ) . FingerprintID )
return activeToken . UserID , agentID , activeToken . ClientID , prefLang , activeToken . ResourceOwner , nil
2023-07-14 11:16:16 +00:00
}
func ( repo * TokenVerifierRepo ) verifySessionToken ( ctx context . Context , sessionID , token string ) ( userID , clientID , resourceOwner string , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-08-04 15:16:27 +00:00
session , err := repo . Query . SessionByID ( ctx , true , sessionID , token )
2023-07-14 11:16:16 +00:00
if err != nil {
return "" , "" , "" , err
}
2023-11-06 09:48:28 +00:00
if ! session . Expiration . IsZero ( ) && session . Expiration . Before ( time . Now ( ) ) {
2023-12-08 14:30:55 +00:00
return "" , "" , "" , zerrors . ThrowPermissionDenied ( nil , "AUTHZ-EGDo3" , "session expired" )
2023-11-06 09:48:28 +00:00
}
2023-07-14 11:16:16 +00:00
if err = repo . checkAuthentication ( ctx , authMethodsFromSession ( session ) , session . UserFactor . UserID ) ; err != nil {
return "" , "" , "" , err
}
return session . UserFactor . UserID , "" , session . UserFactor . ResourceOwner , nil
}
// checkAuthentication ensures the session or token was authenticated (at least a single [domain.UserAuthMethodType]).
2024-05-28 08:59:49 +00:00
// It will also check if there was a multi factor authentication, if either MFA is forced by the login policy or if the user has set up any second factor
2023-07-14 11:16:16 +00:00
func ( repo * TokenVerifierRepo ) checkAuthentication ( ctx context . Context , authMethods [ ] domain . UserAuthMethodType , userID string ) error {
if len ( authMethods ) == 0 {
2023-12-08 14:30:55 +00:00
return zerrors . ThrowPermissionDenied ( nil , "AUTHZ-Kl3p0" , "authentication required" )
2023-07-14 11:16:16 +00:00
}
if domain . HasMFA ( authMethods ) {
return nil
}
2024-05-23 05:35:10 +00:00
requirements , err := repo . Query . ListUserAuthMethodTypesRequired ( setCallerCtx ( ctx , userID ) , userID )
2023-07-14 11:16:16 +00:00
if err != nil {
return err
}
2024-05-23 05:35:10 +00:00
if requirements . UserType == domain . UserTypeMachine {
return nil
}
if domain . RequiresMFA (
requirements . ForceMFA ,
requirements . ForceMFALocalOnly ,
2024-06-12 12:24:17 +00:00
! hasIDPAuthentication ( authMethods ) ,
) {
2023-12-08 14:30:55 +00:00
return zerrors . ThrowPermissionDenied ( nil , "AUTHZ-Kl3p0" , "mfa required" )
2023-07-14 11:16:16 +00:00
}
return nil
}
2023-07-20 04:06:16 +00:00
func hasIDPAuthentication ( authMethods [ ] domain . UserAuthMethodType ) bool {
for _ , method := range authMethods {
if method == domain . UserAuthMethodTypeIDP {
return true
}
}
return false
}
2023-07-14 11:16:16 +00:00
func authMethodsFromSession ( session * query . Session ) [ ] domain . UserAuthMethodType {
types := make ( [ ] domain . UserAuthMethodType , 0 , domain . UserAuthMethodTypeIDP )
if ! session . PasswordFactor . PasswordCheckedAt . IsZero ( ) {
types = append ( types , domain . UserAuthMethodTypePassword )
}
2023-08-11 15:36:18 +00:00
if ! session . WebAuthNFactor . WebAuthNCheckedAt . IsZero ( ) {
if session . WebAuthNFactor . UserVerified {
types = append ( types , domain . UserAuthMethodTypePasswordless )
} else {
types = append ( types , domain . UserAuthMethodTypeU2F )
}
2023-07-14 11:16:16 +00:00
}
if ! session . IntentFactor . IntentCheckedAt . IsZero ( ) {
types = append ( types , domain . UserAuthMethodTypeIDP )
}
2023-09-01 12:53:10 +00:00
if ! session . TOTPFactor . TOTPCheckedAt . IsZero ( ) {
types = append ( types , domain . UserAuthMethodTypeTOTP )
}
2023-08-24 09:41:52 +00:00
if ! session . OTPSMSFactor . OTPCheckedAt . IsZero ( ) {
types = append ( types , domain . UserAuthMethodTypeOTPSMS )
}
if ! session . OTPEmailFactor . OTPCheckedAt . IsZero ( ) {
types = append ( types , domain . UserAuthMethodTypeOTPEmail )
}
2023-07-14 11:16:16 +00:00
return types
}
func setCallerCtx ( ctx context . Context , userID string ) context . Context {
ctxData := authz . GetCtxData ( ctx )
ctxData . UserID = userID
return authz . SetCtxData ( ctx , ctxData )
2020-06-05 05:50:04 +00:00
}
2020-08-24 08:06:55 +00:00
func ( repo * TokenVerifierRepo ) ProjectIDAndOriginsByClientID ( ctx context . Context , clientID string ) ( projectID string , origins [ ] string , err error ) {
2022-03-29 09:53:19 +00:00
app , err := repo . View . ApplicationByOIDCClientID ( ctx , clientID )
2020-06-05 05:50:04 +00:00
if err != nil {
2020-08-24 08:06:55 +00:00
return "" , nil , err
2020-06-05 05:50:04 +00:00
}
2021-11-26 06:57:05 +00:00
return app . ProjectID , app . OIDCConfig . AllowedOrigins , nil
2020-06-05 05:50:04 +00:00
}
2021-11-26 06:57:05 +00:00
func ( repo * TokenVerifierRepo ) VerifierClientID ( ctx context . Context , appName string ) ( clientID , projectID string , err error ) {
2020-10-21 08:18:34 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2022-04-29 12:16:23 +00:00
app , err := repo . View . ApplicationByProjecIDAndAppName ( ctx , authz . GetInstance ( ctx ) . ProjectID ( ) , appName )
2020-06-05 05:50:04 +00:00
if err != nil {
2021-11-26 06:57:05 +00:00
return "" , "" , err
}
if app . OIDCConfig != nil {
clientID = app . OIDCConfig . ClientID
} else if app . APIConfig != nil {
clientID = app . APIConfig . ClientID
2020-06-05 05:50:04 +00:00
}
2021-11-26 06:57:05 +00:00
return clientID , app . ProjectID , nil
2020-06-05 05:50:04 +00:00
}
2021-02-22 13:08:47 +00:00
2023-12-14 10:07:47 +00:00
func ( repo * TokenVerifierRepo ) getUserEvents ( ctx context . Context , userID , instanceID string , changeDate time . Time , eventTypes [ ] eventstore . EventType ) ( _ [ ] eventstore . Event , err error ) {
2022-05-24 09:18:25 +00:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2023-12-14 10:07:47 +00:00
query , err := usr_view . UserByIDQuery ( userID , instanceID , changeDate , eventTypes )
2021-02-22 13:08:47 +00:00
if err != nil {
return nil , err
}
2023-10-19 10:19:10 +00:00
return repo . Eventstore . Filter ( ctx , query )
2022-08-23 06:02:36 +00:00
}
2022-09-15 12:59:40 +00:00
// getTokenIDAndSubject returns the TokenID and Subject of both opaque tokens and JWTs
2022-08-23 06:02:36 +00:00
func ( repo * TokenVerifierRepo ) getTokenIDAndSubject ( ctx context . Context , accessToken string ) ( tokenID string , subject string , valid bool ) {
// accessToken can be either opaque or JWT
// let's try opaque first:
tokenIDSubject , err := repo . decryptAccessToken ( accessToken )
if err != nil {
2023-11-27 15:35:08 +00:00
logging . WithError ( err ) . Warn ( "token verifier repo: decrypt access token" )
2022-08-23 06:02:36 +00:00
// if decryption did not work, it might be a JWT
2023-03-28 11:28:56 +00:00
accessTokenClaims , err := op . VerifyAccessToken [ * oidc . AccessTokenClaims ] ( ctx , accessToken , repo . jwtTokenVerifier ( ctx ) )
2022-08-23 06:02:36 +00:00
if err != nil {
2023-11-27 15:35:08 +00:00
logging . WithError ( err ) . Warn ( "token verifier repo: verify JWT access token" )
2022-08-23 06:02:36 +00:00
return "" , "" , false
}
2023-03-28 11:28:56 +00:00
return accessTokenClaims . JWTID , accessTokenClaims . Subject , true
2022-08-23 06:02:36 +00:00
}
splitToken := strings . Split ( tokenIDSubject , ":" )
if len ( splitToken ) != 2 {
return "" , "" , false
}
return splitToken [ 0 ] , splitToken [ 1 ] , true
}
2023-10-19 10:34:00 +00:00
func ( repo * TokenVerifierRepo ) jwtTokenVerifier ( ctx context . Context ) * op . AccessTokenVerifier {
2022-08-23 06:02:36 +00:00
keySet := & openIDKeySet { repo . Query }
issuer := http_util . BuildOrigin ( authz . GetInstance ( ctx ) . RequestedHost ( ) , repo . ExternalSecure )
return op . NewAccessTokenVerifier ( issuer , keySet )
}
func ( repo * TokenVerifierRepo ) decryptAccessToken ( token string ) ( string , error ) {
tokenData , err := base64 . RawURLEncoding . DecodeString ( token )
if err != nil {
2023-12-08 14:30:55 +00:00
return "" , zerrors . ThrowUnauthenticated ( nil , "APP-ASdgg" , "invalid token" )
2022-08-23 06:02:36 +00:00
}
tokenIDSubject , err := repo . TokenVerificationKey . DecryptString ( tokenData , repo . TokenVerificationKey . EncryptionKeyID ( ) )
if err != nil {
2023-12-08 14:30:55 +00:00
return "" , zerrors . ThrowUnauthenticated ( nil , "APP-8EF0zZ" , "invalid token" )
2022-08-23 06:02:36 +00:00
}
return tokenIDSubject , nil
}
2023-07-14 11:16:16 +00:00
func verifyAudience ( audience [ ] string , verifierClientID , projectID string ) error {
for _ , aud := range audience {
if verifierClientID == aud || projectID == aud {
return nil
}
}
2023-12-08 14:30:55 +00:00
return zerrors . ThrowUnauthenticated ( nil , "APP-Zxfako" , "invalid audience" )
2023-07-14 11:16:16 +00:00
}
2022-08-23 06:02:36 +00:00
type openIDKeySet struct {
* query . Queries
}
2022-09-15 12:59:40 +00:00
// VerifySignature implements the oidc.KeySet interface
// providing an implementation for the keys retrieved directly from Queries
2022-08-23 06:02:36 +00:00
func ( o * openIDKeySet ) VerifySignature ( ctx context . Context , jws * jose . JSONWebSignature ) ( [ ] byte , error ) {
keySet , err := o . Queries . ActivePublicKeys ( ctx , time . Now ( ) )
if err != nil {
return nil , fmt . Errorf ( "error fetching keys: %w" , err )
}
keyID , alg := oidc . GetKeyIDAndAlg ( jws )
key , err := oidc . FindMatchingKey ( keyID , oidc . KeyUseSignature , alg , jsonWebKeys ( keySet . Keys ) ... )
if err != nil {
return nil , fmt . Errorf ( "invalid signature: %w" , err )
}
return jws . Verify ( & key )
}
func jsonWebKeys ( keys [ ] query . PublicKey ) [ ] jose . JSONWebKey {
webKeys := make ( [ ] jose . JSONWebKey , len ( keys ) )
for i , key := range keys {
webKeys [ i ] = jose . JSONWebKey {
KeyID : key . ID ( ) ,
Algorithm : key . Algorithm ( ) ,
Use : key . Use ( ) . String ( ) ,
Key : key . Key ( ) ,
}
}
return webKeys
2021-02-22 13:08:47 +00:00
}