snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
165
selfservice/strategy/oidc/provider.go
Normal file
165
selfservice/strategy/oidc/provider.go
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/dghubble/oauth1"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/ory/herodot"
|
||||
"github.com/ory/kratos/selfservice/strategy/oidc/oidcerr"
|
||||
"github.com/ory/kratos/x"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider interface {
|
||||
Config() *Configuration
|
||||
}
|
||||
OAuth2Provider interface {
|
||||
Provider
|
||||
AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption
|
||||
OAuth2(ctx context.Context) (*oauth2.Config, error)
|
||||
Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error)
|
||||
}
|
||||
OAuth1Provider interface {
|
||||
Provider
|
||||
OAuth1(ctx context.Context) *oauth1.Config
|
||||
AuthURL(ctx context.Context, state string) (string, error)
|
||||
Claims(ctx context.Context, token *oauth1.Token) (*Claims, error)
|
||||
ExchangeToken(ctx context.Context, req *http.Request) (*oauth1.Token, error)
|
||||
}
|
||||
)
|
||||
|
||||
type OAuth2TokenExchanger interface {
|
||||
Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)
|
||||
}
|
||||
|
||||
type IDTokenVerifier interface {
|
||||
Verify(ctx context.Context, rawIDToken string) (*Claims, error)
|
||||
}
|
||||
|
||||
type NonceValidationSkipper interface {
|
||||
CanSkipNonce(*Claims) bool
|
||||
}
|
||||
|
||||
type Claims struct {
|
||||
Issuer string `json:"iss,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Object string `json:"oid,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
GivenName string `json:"given_name,omitempty"`
|
||||
FamilyName string `json:"family_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
MiddleName string `json:"middle_name,omitempty"`
|
||||
Nickname string `json:"nickname,omitempty"`
|
||||
PreferredUsername string `json:"preferred_username,omitempty"`
|
||||
Profile string `json:"profile,omitempty"`
|
||||
Picture string `json:"picture,omitempty"`
|
||||
Website string `json:"website,omitempty"`
|
||||
Email string `json:"email,omitempty"`
|
||||
// ConvertibleBoolean is used as Apple casually sends the email_verified field as a string.
|
||||
EmailVerified x.ConvertibleBoolean `json:"email_verified,omitempty"`
|
||||
Gender string `json:"gender,omitempty"`
|
||||
Birthdate string `json:"birthdate,omitempty"`
|
||||
Zoneinfo string `json:"zoneinfo,omitempty"`
|
||||
Locale Locale `json:"locale,omitempty"`
|
||||
PhoneNumber string `json:"phone_number,omitempty"`
|
||||
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
|
||||
UpdatedAt int64 `json:"updated_at,omitempty"`
|
||||
HD string `json:"hd,omitempty"`
|
||||
Team string `json:"team,omitempty"`
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
NonceSupported bool `json:"nonce_supported,omitempty"`
|
||||
|
||||
// ACR is the Authentication Context Class Reference reported by the
|
||||
// upstream OIDC provider. See OpenID Connect Core 1.0, Section 2.
|
||||
ACR string `json:"acr,omitempty"`
|
||||
|
||||
// AMR is the list of Authentication Methods References reported by the
|
||||
// upstream OIDC provider. See OpenID Connect Core 1.0, Section 2 and
|
||||
// RFC 8176.
|
||||
AMR []string `json:"amr,omitempty"`
|
||||
|
||||
RawClaims map[string]any `json:"raw_claims,omitempty"`
|
||||
}
|
||||
|
||||
type Locale string
|
||||
|
||||
func (l *Locale) UnmarshalJSON(data []byte) error {
|
||||
var linkedInLocale struct {
|
||||
Language string `json:"language"`
|
||||
Country string `json:"country"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &linkedInLocale); err == nil {
|
||||
switch {
|
||||
case linkedInLocale.Language == "":
|
||||
*l = Locale(linkedInLocale.Country)
|
||||
case linkedInLocale.Country == "":
|
||||
*l = Locale(linkedInLocale.Language)
|
||||
default:
|
||||
*l = Locale(strings.Join([]string{linkedInLocale.Language, linkedInLocale.Country}, "-"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, (*string)(l))
|
||||
}
|
||||
|
||||
// Validate checks if the claims are valid.
|
||||
func (c *Claims) Validate() error {
|
||||
if c.Subject == "" {
|
||||
return oidcerr.Wrap(oidcerr.StepClaimsDecode, errors.WithStack(herodot.ErrUpstreamError().WithReasonf("provider did not return a subject")))
|
||||
}
|
||||
if c.Issuer == "" {
|
||||
return oidcerr.Wrap(oidcerr.StepClaimsDecode, errors.WithStack(herodot.ErrUpstreamError().WithReasonf("issuer not set in claims")))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpstreamParameters returns a list of oauth2.AuthCodeOption based on the upstream parameters.
|
||||
//
|
||||
// Only allowed parameters are returned and the rest is ignored.
|
||||
// Allowed parameters are also defined in the `oidc/.schema/link.schema.json` file, however,
|
||||
// this function also validates the parameters to prevent any potential security issues.
|
||||
//
|
||||
// Allowed parameters are:
|
||||
// - `hd` (string): The `hd` parameter limits the login/registration process to a Google Organization, e.g. `mycollege.edu`.
|
||||
// - `prompt` (string): The `prompt` specifies whether the Authorization Server prompts the End-User for reauthentication and consent, e.g. `select_account`.
|
||||
// - `auth_type` (string): The `auth_type` parameter specifies the requested authentication features (as a comma-separated list), e.g. `reauthenticate`.
|
||||
// - `acr_values` (string): The `acr_values` specifies the Authentication Context Class Reference values for the authorization request.
|
||||
//
|
||||
// `login_hint` is intentionally not forwarded. A caller-supplied value cannot be
|
||||
// trusted, and on IdPs that act on it (Google, Microsoft, Auth0, …) it can steer
|
||||
// account, tenant, or OAuth client selection and enable a client-swap attack
|
||||
// (HackerOne #3239672, ory-corp/cloud#8955).
|
||||
func UpstreamParameters(upstreamParameters map[string]string) []oauth2.AuthCodeOption {
|
||||
// validation of upstream parameters are already handled in the `oidc/.schema/link.schema.json` and `oidc/.schema/settings.schema.json` file.
|
||||
// `upstreamParameters` will always only contain allowed parameters based on the configuration.
|
||||
|
||||
// we double-check the parameters here to prevent any potential security issues.
|
||||
allowedParameters := map[string]struct{}{
|
||||
"hd": {},
|
||||
"prompt": {},
|
||||
"auth_type": {},
|
||||
"acr_values": {},
|
||||
}
|
||||
|
||||
var params []oauth2.AuthCodeOption
|
||||
for up, v := range upstreamParameters {
|
||||
if _, ok := allowedParameters[up]; !ok {
|
||||
continue
|
||||
}
|
||||
params = append(params, oauth2.SetAuthURLParam(up, v))
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
Reference in New Issue
Block a user