introduce oidc middleware

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2019-12-11 15:32:22 +01:00
committed by Thomas Müller
parent 036f94467d
commit d9e0380d80
7 changed files with 612 additions and 7 deletions
+228
View File
@@ -0,0 +1,228 @@
package oidc
// The ProviderMetadata describes an idp.
// see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
type ProviderMetadata struct {
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
//claims_parameter_supported
ClaimsSupported []string `json:"claims_supported,omitempty"`
//grant_types_supported
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported,omitempty"`
Issuer string `json:"issuer,omitempty"`
JwksURI string `json:"jwks_uri,omitempty"`
//registration_endpoint
//request_object_signing_alg_values_supported
//request_parameter_supported
//request_uri_parameter_supported
//require_request_uri_registration
//response_modes_supported
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
SubjectTypesSupported []string `json:"subject_types_supported,omitempty"`
TokenEndpoint string `json:"token_endpoint,omitempty"`
//token_endpoint_auth_methods_supported
//token_endpoint_auth_signing_alg_values_supported
UserinfoEndpoint string `json:"userinfo_endpoint,omitempty"`
//userinfo_signing_alg_values_supported
//code_challenge_methods_supported
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
//introspection_endpoint_auth_methods_supported
//introspection_endpoint_auth_signing_alg_values_supported
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
//revocation_endpoint_auth_methods_supported
//revocation_endpoint_auth_signing_alg_values_supported
//id_token_encryption_alg_values_supported
//id_token_encryption_enc_values_supported
//userinfo_encryption_alg_values_supported
//userinfo_encryption_enc_values_supported
//request_object_encryption_alg_values_supported
//request_object_encryption_enc_values_supported
CheckSessionIframe string `json:"check_session_iframe,omitempty"`
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
//claim_types_supported
}
// StandardClaims will be stored in the context to be consumed by the oidc user manager
// They can be requested to be returned either in the UserInfo Response, per
// Section 5.3.2, or in the ID Token, per Section 2.
// see https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
type StandardClaims struct {
// Time the End-User's information was last updated. Its value is a
// JSON number representing the number of seconds from 1970-01-01T0:0:0Z
// as measured in UTC until the date/time.
UpdatedAt int64 `json:"updated_at,omitempty"`
// True if the End-User's e-mail address has been verified; otherwise false.
// When this Claim Value is true, this means that the OP took affirmative
// steps to ensure that this e-mail address was controlled by the End-User
// at the time the verification was performed. The means by which an e-mail
// address is verified is context-specific, and dependent upon the trust
// framework or contractual agreements within which the parties are operating.
EmailVerified bool `json:"email_verified,omitempty"`
// True if the End-User's phone number has been verified; otherwise false.
// When this Claim Value is true, this means that the OP took affirmative
// steps to ensure that this phone number was controlled by the End-User
// at the time the verification was performed. The means by which a phone
// number is verified is context-specific, and dependent upon the trust
// framework or contractual agreements within which the parties are
// operating. When true, the phone_number Claim MUST be in E.164 format
// and any extensions MUST be represented in RFC 3966 format.
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
Iss string `json:"iss"`
// Subject - Identifier for the End-User at the Issuer.
Sub string `json:"sub,omitempty"`
// End-User's full name in displayable form including all name parts, possibly
// including titles and suffixes, ordered according to the End-User's locale
// and preferences.
Name string `json:"name,omitempty"`
// Given name(s) or first name(s) of the End-User. Note that in some cultures,
// people can have multiple given names; all can be present, with the names
// being separated by space characters.
GivenName string `json:"given_name,omitempty"`
// Surname(s) or last name(s) of the End-User. Note that in some cultures,
// people can have multiple family names or no family name; all can be present,
// with the names being separated by space characters.
FamilyName string `json:"family_name,omitempty"`
// Middle name(s) of the End-User. Note that in some cultures, people can have
// multiple middle names; all can be present, with the names being separated by
// space characters. Also note that in some cultures, middle names are not used.
MiddleName string `json:"middle_name,omitempty"`
// Casual name of the End-User that may or may not be the same as the given_name.
// For instance, a nickname value of Mike might be returned alongside a given_name
// value of Michael.
Nickname string `json:"nickname,omitempty"`
// Shorthand name by which the End-User wishes to be referred to at the RP, such
// as janedoe or j.doe. This value MAY be any valid JSON string including special
// characters such as @, /, or whitespace. The RP MUST NOT rely upon this value
// being unique, as discussed in Section 5.7.
PreferredUsername string `json:"preferred_username,omitempty"`
// URL of the End-User's profile page. The contents of this Web page SHOULD be
// about the End-User.
Profile string `json:"profile,omitempty"`
// URL of the End-User's profile picture. This URL MUST refer to an image file
// (for example, a PNG, JPEG, or GIF image file), rather than to a Web page
// containing an image. Note that this URL SHOULD specifically reference a
// profile photo of the End-User suitable for displaying when describing the
// End-User, rather than an arbitrary photo taken by the End-User.
Picture string `json:"picture,omitempty"`
// URL of the End-User's Web page or blog. This Web page SHOULD contain
// information published by the End-User or an organization that the End-User
// is affiliated with.
Website string `json:"website,omitempty"`
// End-User's preferred e-mail address. Its value MUST conform to the RFC 5322
// addr-spec syntax. The RP MUST NOT rely upon this value being unique, as
// discussed in Section 5.7.
Email string `json:"email,omitempty"`
// End-User's gender. Values defined by this specification are female and male.
// Other values MAY be used when neither of the defined values are applicable.
Gender string `json:"gender,omitempty"`
// End-User's birthday, represented as an ISO 8601:2004 YYYY-MM-DD format.
// The year MAY be 0000, indicating that it is omitted. To represent only the
// year, YYYY format is allowed. Note that depending on the underlying
// platform's date related function, providing just year can result in
// varying month and day, so the implementers need to take this factor into
// account to correctly process the dates.
Birthdate string `json:"birthdate,omitempty"`
// String from zoneinfo time zone database representing the End-User's time
// zone. For example, Europe/Paris or America/Los_Angeles.
Zoneinfo string `json:"zoneinfo,omitempty"`
// End-User's locale, represented as a BCP47 [RFC5646] language tag.
// This is typically an ISO 639-1 Alpha-2 [ISO6391] language code in
// lowercase and an ISO 3166-1 Alpha-2 [ISO31661] country code in
// uppercase, separated by a dash. For example, en-US or fr-CA. As a
// compatibility note, some implementations have used an underscore as
// the separator rather than a dash, for example, en_US; Relying Parties
// MAY choose to accept this locale syntax as well.
Locale string `json:"locale,omitempty"`
// End-User's preferred telephone number. E.164 [E.164] is RECOMMENDED
// as the format of this Claim, for example, +1 (425) 555-1212 or
// +56 (2) 687 2400. If the phone number contains an extension, it is
// RECOMMENDED that the extension be represented using the RFC 3966
// extension syntax, for example, +1 (604) 555-1234;ext=5678.
PhoneNumber string `json:"phone_number,omitempty"`
// TODO Name is the correct one, does kopano use display name? -> double check and report bug
DisplayName string `json:"display_name,omitempty"`
Groups []string `json:"groups,omitempty"`
// End-User's preferred postal address. The value of the address member
// is a JSON [RFC4627] structure containing some or all of the members
// defined in Section 5.1.1.
// TODO add address claim https://openid.net/specs/openid-connect-core-1_0.html#AddressClaim
Address map[string]interface{} `json:"address,omitempty"`
KCIdentity map[string]string `json:"kc.identity,omitempty"`
}
// The IntrospectionResponse is a JSON object [RFC7159] in
// "application/json" format with the following top-level members.
// see https://tools.ietf.org/html/rfc7662#section-2.2
type IntrospectionResponse struct {
// REQUIRED. Boolean indicator of whether or not the presented token
// is currently active. The specifics of a token's "active" state
// will vary depending on the implementation of the authorization
// server and the information it keeps about its tokens, but a "true"
// value return for the "active" property will generally indicate
// that a given token has been issued by this authorization server,
// has not been revoked by the resource owner, and is within its
// given time window of validity (e.g., after its issuance time and
// before its expiration time). See Section 4 for information on
// implementation of such checks.
Active bool `json:"active"`
// OPTIONAL. A JSON string containing a space-separated list of
// scopes associated with this token, in the format described in
// Section 3.3 of OAuth 2.0 [RFC6749].
Scope string `json:"scope,omitempty"`
// OPTIONAL. Client identifier for the OAuth 2.0 client that
// requested this token.
ClientID string `json:"client_id,omitempty"`
// OPTIONAL. Human-readable identifier for the resource owner who
// authorized this token.
Username string `json:"username,omitempty"`
// OPTIONAL. Type of the token as defined in Section 5.1 of OAuth
// 2.0 [RFC6749].
TokenType string `json:"token_type,omitempty"`
// OPTIONAL. Integer timestamp, measured in the number of seconds
// since January 1 1970 UTC, indicating when this token will expire,
// as defined in JWT [RFC7519].
Exp int64 `json:"exp,omitempty"`
// OPTIONAL. Integer timestamp, measured in the number of seconds
// since January 1 1970 UTC, indicating when this token was
// originally issued, as defined in JWT [RFC7519].
Iat int64 `json:"iat,omitempty"`
// OPTIONAL. Integer timestamp, measured in the number of seconds
// since January 1 1970 UTC, indicating when this token is not to be
// used before, as defined in JWT [RFC7519].
Nbf int64 `json:"nbf,omitempty"`
// OPTIONAL. Subject of the token, as defined in JWT [RFC7519].
// Usually a machine-readable identifier of the resource owner who
// authorized this token.
Sub string `json:"sub,omitempty"`
// OPTIONAL. Service-specific string identifier or list of string
// identifiers representing the intended audience for this token, as
// defined in JWT [RFC7519].
Aud string `json:"aud,omitempty"`
// OPTIONAL. String representing the issuer of this token, as
// defined in JWT [RFC7519].
Iss string `json:"iss,omitempty"`
// OPTIONAL. String identifier for the token, as defined in JWT [RFC7519].
Jti string `json:"jti,omitempty"`
}
+17
View File
@@ -0,0 +1,17 @@
package oidc
import "context"
// contextKey is the key for oidc claims in a context
type contextKey struct{}
// NewContext makes a new context that contains the OpenID Connect claims.
func NewContext(parent context.Context, c *StandardClaims) context.Context {
return context.WithValue(parent, contextKey{}, c)
}
// FromContext returns the StandardClaims stored in a context, or nil if there isn't one.
func FromContext(ctx context.Context) *StandardClaims {
s, _ := ctx.Value(contextKey{}).(*StandardClaims)
return s
}
+93
View File
@@ -0,0 +1,93 @@
package oidc
import (
"github.com/owncloud/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
// Logger to use for logging, must be set
Logger log.Logger
// Endpoint is the OpenID Connect provider URL
Endpoint string
// Realm to use in the WWW-Authenticate header, defaults to Endpoint
Realm string
// Audience to use when checking jwt based tokens
Audience string
// SigningAlgs to use when verifying jwt signatures, defaults to "RS256" & "PS256"
SigningAlgs []string
// ClientId to use as username for basic auth against the introspection endpoint
ClientID string
// ClientSecret to use as password for basic auth against the introspection endpoint
ClientSecret string
// Insecure can be used to disable http certificate checks
Insecure bool
// SkipCheck can be used to further reduce security. Fix that!
SkipChecks bool
}
// Logger provides a function to set the logger option.
func Logger(l log.Logger) Option {
return func(o *Options) {
o.Logger = l
}
}
// Endpoint provides a function to set the endpoint option.
func Endpoint(e string) Option {
return func(o *Options) {
o.Endpoint = e
}
}
// Realm provides a function to set the realm option.
func Realm(r string) Option {
return func(o *Options) {
o.Realm = r
}
}
// Audience provides a function to set the audience option.
func Audience(a string) Option {
return func(o *Options) {
o.Audience = a
}
}
// SigningAlgs provides a function to set the signing algorithms option.
func SigningAlgs(sa []string) Option {
return func(o *Options) {
o.SigningAlgs = sa
}
}
// ClientID provides a function to set the client id option.
func ClientID(ci string) Option {
return func(o *Options) {
o.ClientID = ci
}
}
// ClientSecret provides a function to set the client secret option.
func ClientSecret(cs string) Option {
return func(o *Options) {
o.ClientSecret = cs
}
}
// Insecure provides a function to set the insecure option.
func Insecure(i bool) Option {
return func(o *Options) {
o.Insecure = i
}
}
// SkipChecks provides a function to set the ready option.
func SkipChecks(sc bool) Option {
return func(o *Options) {
o.SkipChecks = sc
}
}