2021-05-04 22:06:05 +00:00
package handlers
import (
2022-03-15 22:55:38 +00:00
"errors"
2021-05-04 22:06:05 +00:00
"net/http"
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
"time"
2021-05-04 22:06:05 +00:00
2022-04-07 05:33:53 +00:00
"github.com/google/uuid"
2021-05-04 22:06:05 +00:00
"github.com/ory/fosite"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/middlewares"
2022-04-01 11:18:58 +00:00
"github.com/authelia/authelia/v4/internal/model"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/oidc"
2021-05-04 22:06:05 +00:00
)
2022-04-07 00:58:51 +00:00
// OpenIDConnectAuthorizationGET handles GET requests to the OpenID Connect 1.0 Authorization endpoint.
//
// https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
func OpenIDConnectAuthorizationGET ( ctx * middlewares . AutheliaCtx , rw http . ResponseWriter , r * http . Request ) {
2022-03-15 22:55:38 +00:00
var (
requester fosite . AuthorizeRequester
responder fosite . AuthorizeResponder
2022-04-07 05:33:53 +00:00
client * oidc . Client
2022-03-15 22:55:38 +00:00
authTime time . Time
issuer string
err error
)
if requester , err = ctx . Providers . OpenIDConnect . Fosite . NewAuthorizeRequest ( ctx , r ) ; err != nil {
rfc := fosite . ErrorToRFC6749Error ( err )
2022-04-12 11:39:15 +00:00
ctx . Logger . Errorf ( "Authorization Request failed with error: %s" , rfc . GetDescription ( ) )
2022-03-15 22:55:38 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , err )
return
}
clientID := requester . GetClient ( ) . GetID ( )
ctx . Logger . Debugf ( "Authorization Request with id '%s' on client with id '%s' is being processed" , requester . GetID ( ) , clientID )
2022-04-07 05:33:53 +00:00
if client , err = ctx . Providers . OpenIDConnect . Store . GetFullClient ( clientID ) ; err != nil {
2022-03-15 22:55:38 +00:00
if errors . Is ( err , fosite . ErrNotFound ) {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: client was not found" , requester . GetID ( ) , clientID )
} else {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: failed to find client: %+v" , requester . GetID ( ) , clientID , err )
}
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , err )
2021-05-04 22:06:05 +00:00
return
}
2022-03-15 22:55:38 +00:00
if issuer , err = ctx . ExternalRootURL ( ) ; err != nil {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred determining issuer: %+v" , requester . GetID ( ) , clientID , err )
2021-05-04 22:06:05 +00:00
2022-03-15 22:55:38 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , fosite . ErrServerError . WithHint ( "Could not determine issuer." ) )
2021-05-04 22:06:05 +00:00
return
}
userSession := ctx . GetSession ( )
2022-04-07 05:33:53 +00:00
var subject uuid . UUID
2021-05-04 22:06:05 +00:00
2022-04-07 05:33:53 +00:00
if subject , err = ctx . Providers . OpenIDConnect . Store . GetSubject ( ctx , client . GetSectorIdentifier ( ) , userSession . Username ) ; err != nil {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred retrieving subject for user '%s': %+v" , requester . GetID ( ) , client . GetID ( ) , userSession . Username , err )
2021-05-04 22:06:05 +00:00
2022-04-07 05:33:53 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , fosite . ErrServerError . WithHint ( "Could not retrieve the subject." ) )
2021-05-04 22:06:05 +00:00
return
}
2022-04-07 05:33:53 +00:00
var (
consent * model . OAuth2ConsentSession
handled bool
)
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
2022-04-07 05:33:53 +00:00
if consent , handled = handleOIDCAuthorizationConsent ( ctx , issuer , client , userSession , subject , rw , r , requester ) ; handled {
feat(oidc): add additional config options, accurate token times, and refactoring (#1991)
* This gives admins more control over their OIDC installation exposing options that had defaults before. Things like lifespans for authorize codes, access tokens, id tokens, refresh tokens, a option to enable the debug client messages, minimum parameter entropy. It also allows admins to configure the response modes.
* Additionally this records specific values about a users session indicating when they performed a specific authz factor so this is represented in the token accurately.
* Lastly we also implemented a OIDC key manager which calculates the kid for jwk's using the SHA1 digest instead of being static, or more specifically the first 7 chars. As per https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key#section-8.1.1 the kid should not exceed 8 chars. While it's allowed to exceed 8 chars, it must only be done so with a compelling reason, which we do not have.
2021-07-03 23:44:30 +00:00
return
}
2022-04-07 05:33:53 +00:00
extraClaims := oidcGrantRequests ( requester , consent , & userSession )
2022-03-15 22:55:38 +00:00
if authTime , err = userSession . AuthenticatedTime ( client . Policy ) ; err != nil {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred checking authentication time: %+v" , requester . GetID ( ) , client . GetID ( ) , err )
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , fosite . ErrServerError . WithHint ( "Could not obtain the authentication time." ) )
2021-05-04 22:06:05 +00:00
return
}
2022-03-15 22:55:38 +00:00
ctx . Logger . Debugf ( "Authorization Request with id '%s' on client with id '%s' was successfully processed, proceeding to build Authorization Response" , requester . GetID ( ) , clientID )
oidcSession := oidc . NewSessionWithAuthorizeRequest ( issuer , ctx . Providers . OpenIDConnect . KeyManager . GetActiveKeyID ( ) ,
2022-04-07 05:33:53 +00:00
userSession . Username , userSession . AuthenticationMethodRefs . MarshalRFC8176 ( ) , extraClaims , authTime , consent , requester )
2022-03-15 22:55:38 +00:00
ctx . Logger . Tracef ( "Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with claims: %+v" ,
requester . GetID ( ) , oidcSession . ClientID , oidcSession . Subject , oidcSession . Username , oidcSession . Claims )
ctx . Logger . Tracef ( "Authorization Request with id '%s' on client with id '%s' creating session for Authorization Response for subject '%s' with username '%s' with headers: %+v" ,
requester . GetID ( ) , oidcSession . ClientID , oidcSession . Subject , oidcSession . Username , oidcSession . Headers )
if responder , err = ctx . Providers . OpenIDConnect . Fosite . NewAuthorizeResponse ( ctx , requester , oidcSession ) ; err != nil {
rfc := fosite . ErrorToRFC6749Error ( err )
2022-04-12 11:39:15 +00:00
ctx . Logger . Errorf ( "Authorization Response for Request with id '%s' on client with id '%s' could not be created: %s" , requester . GetID ( ) , clientID , rfc . GetDescription ( ) )
2022-03-15 22:55:38 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , err )
2021-05-04 22:06:05 +00:00
return
}
2022-04-07 05:33:53 +00:00
if err = ctx . Providers . StorageProvider . SaveOAuth2ConsentSessionGranted ( ctx , consent . ID ) ; err != nil {
ctx . Logger . Errorf ( "Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred saving consent session: %+v" , requester . GetID ( ) , client . GetID ( ) , err )
2022-03-15 22:55:38 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeError ( rw , requester , fosite . ErrServerError . WithHint ( "Could not save the session." ) )
2021-05-04 22:06:05 +00:00
return
}
2022-04-07 05:33:53 +00:00
ctx . Providers . OpenIDConnect . Fosite . WriteAuthorizeResponse ( rw , requester , responder )
2021-05-04 22:06:05 +00:00
}