2021-07-10 11:56:33 +07:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/ory/fosite"
|
|
|
|
"github.com/ory/fosite/token/jwt"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
2021-08-11 08:04:35 +07:00
|
|
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
|
|
|
"github.com/authelia/authelia/v4/internal/oidc"
|
2021-07-10 11:56:33 +07:00
|
|
|
)
|
|
|
|
|
|
|
|
func oidcUserinfo(ctx *middlewares.AutheliaCtx, rw http.ResponseWriter, req *http.Request) {
|
|
|
|
session := newOpenIDSession("")
|
|
|
|
|
|
|
|
tokenType, ar, err := ctx.Providers.OpenIDConnect.Fosite.IntrospectToken(req.Context(), fosite.AccessTokenFromRequest(req), fosite.AccessToken, session)
|
|
|
|
if err != nil {
|
|
|
|
rfc := fosite.ErrorToRFC6749Error(err)
|
|
|
|
if rfc.StatusCode() == http.StatusUnauthorized {
|
|
|
|
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("error=%s,error_description=%s", rfc.ErrorField, rfc.GetDescription()))
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if tokenType != fosite.AccessToken {
|
2021-09-17 12:53:40 +07:00
|
|
|
errStr := "authorization header must contain an OAuth access token."
|
2021-07-10 11:56:33 +07:00
|
|
|
rw.Header().Set("WWW-Authenticate", fmt.Sprintf("error_description=\"%s\"", errStr))
|
|
|
|
ctx.Providers.OpenIDConnect.WriteErrorCode(rw, req, http.StatusUnauthorized, errors.New(errStr))
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
client, ok := ar.GetClient().(*oidc.InternalClient)
|
|
|
|
if !ok {
|
|
|
|
ctx.Providers.OpenIDConnect.WriteError(rw, req, errors.WithStack(fosite.ErrServerError.WithHint("Unable to assert type of client")))
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
claims := ar.GetSession().(*oidc.OpenIDSession).IDTokenClaims().ToMap()
|
|
|
|
delete(claims, "jti")
|
|
|
|
delete(claims, "sid")
|
|
|
|
delete(claims, "at_hash")
|
|
|
|
delete(claims, "c_hash")
|
|
|
|
delete(claims, "exp")
|
|
|
|
delete(claims, "nonce")
|
|
|
|
|
|
|
|
if audience, ok := claims["aud"].([]string); !ok || len(audience) == 0 {
|
|
|
|
claims["aud"] = []string{client.GetID()}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch client.UserinfoSigningAlgorithm {
|
|
|
|
case "RS256":
|
|
|
|
claims["jti"] = uuid.New()
|
|
|
|
claims["iat"] = time.Now().Unix()
|
|
|
|
|
|
|
|
keyID, err := ctx.Providers.OpenIDConnect.KeyManager.Strategy().GetPublicKeyID(req.Context())
|
|
|
|
if err != nil {
|
|
|
|
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
token, _, err := ctx.Providers.OpenIDConnect.KeyManager.Strategy().Generate(req.Context(), claims,
|
|
|
|
&jwt.Headers{
|
|
|
|
Extra: map[string]interface{}{"kid": keyID},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
ctx.Providers.OpenIDConnect.WriteError(rw, req, err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
rw.Header().Set("Content-Type", "application/jwt")
|
|
|
|
_, _ = rw.Write([]byte(token))
|
|
|
|
case "none", "":
|
|
|
|
ctx.Providers.OpenIDConnect.Write(rw, req, claims)
|
|
|
|
default:
|
|
|
|
ctx.Providers.OpenIDConnect.WriteError(rw, req, errors.WithStack(fosite.ErrServerError.WithHintf("Unsupported userinfo signing algorithm '%s'.", client.UserinfoSigningAlgorithm)))
|
|
|
|
}
|
|
|
|
}
|