2020-06-05 07:50:04 +02:00
package oidc
import (
"context"
2020-07-09 14:05:12 +02:00
"fmt"
2020-10-16 07:49:38 +02:00
"strings"
2020-06-05 07:50:04 +02:00
"time"
"github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op"
"gopkg.in/square/go-jose.v2"
2020-08-31 08:49:35 +02:00
"github.com/caos/zitadel/internal/api/http/middleware"
2020-06-05 07:50:04 +02:00
"github.com/caos/zitadel/internal/errors"
2020-10-16 07:49:38 +02:00
proj_model "github.com/caos/zitadel/internal/project/model"
2020-12-02 08:50:59 +01:00
"github.com/caos/zitadel/internal/telemetry/tracing"
2020-07-09 14:05:12 +02:00
grant_model "github.com/caos/zitadel/internal/usergrant/model"
2020-06-05 07:50:04 +02:00
)
2020-10-21 10:18:34 +02: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 ) } ( )
2020-08-31 08:49:35 +02:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
2020-06-05 07:50:04 +02:00
if ! ok {
return nil , errors . ThrowPreconditionFailed ( nil , "OIDC-sd436" , "no user agent id" )
}
2020-10-16 07:49:38 +02:00
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" )
}
2020-06-05 07:50:04 +02:00
authRequest := CreateAuthRequestToBusiness ( ctx , req , userAgentID , userID )
resp , err := o . repo . CreateAuthRequest ( ctx , authRequest )
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2020-10-21 10:18:34 +02:00
func ( o * OPStorage ) AuthRequestByID ( ctx context . Context , id string ) ( _ op . AuthRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-08-31 08:49:35 +02:00
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 )
2020-06-05 07:50:04 +02:00
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2020-10-21 10:18:34 +02:00
func ( o * OPStorage ) AuthRequestByCode ( ctx context . Context , code string ) ( _ op . AuthRequest , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-06-05 07:50:04 +02:00
resp , err := o . repo . AuthRequestByCode ( ctx , code )
if err != nil {
return nil , err
}
return AuthRequestFromBusiness ( resp )
}
2020-10-21 10:18:34 +02:00
func ( o * OPStorage ) SaveAuthCode ( ctx context . Context , id , code string ) ( err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-08-31 08:49:35 +02:00
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 )
2020-06-05 07:50:04 +02:00
}
2020-10-21 10:18:34 +02:00
func ( o * OPStorage ) DeleteAuthRequest ( ctx context . Context , id string ) ( err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-06-05 07:50:04 +02:00
return o . repo . DeleteAuthRequest ( ctx , id )
}
2021-05-20 13:33:35 +02:00
func ( o * OPStorage ) CreateAccessToken ( ctx context . Context , req op . TokenRequest ) ( _ string , _ time . Time , err error ) {
2020-10-21 10:18:34 +02:00
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2021-03-29 14:50:58 +02:00
var userAgentID , applicationID , userOrgID string
2020-09-17 08:49:33 +02:00
authReq , ok := req . ( * AuthRequest )
if ok {
userAgentID = authReq . AgentID
applicationID = authReq . ApplicationID
2021-03-29 14:50:58 +02:00
userOrgID = authReq . UserOrgID
2020-07-09 14:05:12 +02:00
}
2021-03-29 14:50:58 +02:00
resp , err := o . command . AddUserToken ( ctx , userOrgID , userAgentID , applicationID , req . GetSubject ( ) , req . GetAudience ( ) , req . GetScopes ( ) , o . defaultAccessTokenLifetime ) //PLANNED: lifetime from client
2020-06-05 07:50:04 +02:00
if err != nil {
return "" , time . Time { } , err
}
2020-10-15 13:52:41 +02:00
return resp . TokenID , resp . Expiration , nil
2020-06-05 07:50:04 +02:00
}
2020-07-09 14:05:12 +02:00
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
}
2021-05-20 13:33:35 +02: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 ) } ( )
2021-05-26 09:01:07 +02:00
userAgentID , applicationID , userOrgID , authTime , authMethodsReferences := getInfoFromRequest ( req )
2021-05-20 13:33:35 +02:00
resp , token , err := o . command . AddAccessAndRefreshToken ( ctx , userOrgID , userAgentID , applicationID , req . GetSubject ( ) ,
refreshToken , req . GetAudience ( ) , req . GetScopes ( ) , authMethodsReferences , o . defaultAccessTokenLifetime ,
o . defaultRefreshTokenIdleExpiration , o . defaultRefreshTokenExpiration , authTime ) //PLANNED: lifetime from client
if err != nil {
return "" , "" , time . Time { } , err
}
return resp . TokenID , token , resp . Expiration , nil
}
2021-05-26 09:01:07 +02: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
}
2021-05-20 13:33:35 +02:00
func ( o * OPStorage ) TokenRequestByRefreshToken ( ctx context . Context , refreshToken string ) ( op . RefreshTokenRequest , error ) {
tokenView , err := o . repo . RefreshTokenByID ( ctx , refreshToken )
if err != nil {
return nil , err
}
return RefreshTokenRequestFromBusiness ( tokenView ) , nil
}
2020-10-21 10:18:34 +02: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 08:49:35 +02:00
userAgentID , ok := middleware . UserAgentIDFromCtx ( ctx )
2020-06-05 07:50:04 +02:00
if ! ok {
return errors . ThrowPreconditionFailed ( nil , "OIDC-fso7F" , "no user agent id" )
}
2021-02-08 11:30:30 +01:00
userIDs , err := o . repo . UserSessionUserIDsByAgentID ( ctx , userAgentID )
if err != nil {
return err
}
return o . command . HumansSignOut ( ctx , userAgentID , userIDs )
2020-06-05 07:50:04 +02:00
}
2021-02-23 08:32:00 +01:00
func ( o * OPStorage ) GetSigningKey ( ctx context . Context , keyCh chan <- jose . SigningKey ) {
o . repo . GetSigningKey ( ctx , keyCh , o . signingKeyAlgorithm )
2020-06-05 07:50:04 +02:00
}
2020-10-21 10:18:34 +02:00
func ( o * OPStorage ) GetKeySet ( ctx context . Context ) ( _ * jose . JSONWebKeySet , err error ) {
ctx , span := tracing . NewSpan ( ctx )
defer func ( ) { span . EndWithError ( err ) } ( )
2020-06-05 07:50:04 +02:00
return o . repo . GetKeySet ( ctx )
}
2020-10-16 07:49:38 +02:00
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
}