mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-01-08 04:03:58 +02:00
c900c51a1b
* Unbreak oauth2-proxy for keycloak provider after 2c668a With 2c668a, oauth2-proxy fails a request if the token validation fails. Token validation always fails with the keycloak provider, due to the valudation request passing the token via the URL, and keycloak not parsing the url for tokens. This is fixed by forcing the validation request to pass the token via a header. This code taken from the DigitalOcean provider, which presumably forcing the token to be passed via header for the same reason. Test plan: I was unable to build a docker image to test the fix, but I believe it is relatively simple, and it passes the "looks good to me" test plan. * Add changelog entry for unbreak keycloak Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
108 lines
2.7 KiB
Go
108 lines
2.7 KiB
Go
package providers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
|
|
)
|
|
|
|
type KeycloakProvider struct {
|
|
*ProviderData
|
|
}
|
|
|
|
var _ Provider = (*KeycloakProvider)(nil)
|
|
|
|
const (
|
|
keycloakProviderName = "Keycloak"
|
|
keycloakDefaultScope = "api"
|
|
)
|
|
|
|
var (
|
|
// Default Login URL for Keycloak.
|
|
// Pre-parsed URL of https://keycloak.org/oauth/authorize.
|
|
keycloakDefaultLoginURL = &url.URL{
|
|
Scheme: "https",
|
|
Host: "keycloak.org",
|
|
Path: "/oauth/authorize",
|
|
}
|
|
|
|
// Default Redeem URL for Keycloak.
|
|
// Pre-parsed URL of ttps://keycloak.org/oauth/token.
|
|
keycloakDefaultRedeemURL = &url.URL{
|
|
Scheme: "https",
|
|
Host: "keycloak.org",
|
|
Path: "/oauth/token",
|
|
}
|
|
|
|
// Default Validation URL for Keycloak.
|
|
// Pre-parsed URL of https://keycloak.org/api/v3/user.
|
|
keycloakDefaultValidateURL = &url.URL{
|
|
Scheme: "https",
|
|
Host: "keycloak.org",
|
|
Path: "/api/v3/user",
|
|
}
|
|
)
|
|
|
|
// NewKeycloakProvider creates a KeyCloakProvider using the passed ProviderData
|
|
func NewKeycloakProvider(p *ProviderData, opts options.KeycloakOptions) *KeycloakProvider {
|
|
p.setProviderDefaults(providerDefaults{
|
|
name: keycloakProviderName,
|
|
loginURL: keycloakDefaultLoginURL,
|
|
redeemURL: keycloakDefaultRedeemURL,
|
|
profileURL: nil,
|
|
validateURL: keycloakDefaultValidateURL,
|
|
scope: keycloakDefaultScope,
|
|
})
|
|
|
|
provider := &KeycloakProvider{ProviderData: p}
|
|
provider.setAllowedGroups(opts.Groups)
|
|
return provider
|
|
}
|
|
|
|
// EnrichSession uses the Keycloak userinfo endpoint to populate the session's
|
|
// email and groups.
|
|
func (p *KeycloakProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
|
|
// Fallback to ValidateURL if ProfileURL not set for legacy compatibility
|
|
profileURL := p.ValidateURL.String()
|
|
if p.ProfileURL.String() != "" {
|
|
profileURL = p.ProfileURL.String()
|
|
}
|
|
|
|
json, err := requests.New(profileURL).
|
|
WithContext(ctx).
|
|
SetHeader("Authorization", "Bearer "+s.AccessToken).
|
|
Do().
|
|
UnmarshalJSON()
|
|
if err != nil {
|
|
logger.Errorf("failed making request %v", err)
|
|
return err
|
|
}
|
|
|
|
groups, err := json.Get("groups").StringArray()
|
|
if err == nil {
|
|
for _, group := range groups {
|
|
if group != "" {
|
|
s.Groups = append(s.Groups, group)
|
|
}
|
|
}
|
|
}
|
|
|
|
email, err := json.Get("email").String()
|
|
if err != nil {
|
|
return fmt.Errorf("unable to extract email from userinfo endpoint: %v", err)
|
|
}
|
|
s.Email = email
|
|
|
|
return nil
|
|
}
|
|
|
|
// ValidateSession validates the AccessToken
|
|
func (p *KeycloakProvider) ValidateSession(ctx context.Context, s *sessions.SessionState) bool {
|
|
return validateToken(ctx, p, s.AccessToken, makeOIDCHeader(s.AccessToken))
|
|
}
|