Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dex
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
dex
Commits
e80701f4
Commit
e80701f4
authored
Jan 13, 2016
by
Eric Chiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Godeps: update go-oidc for updates to client and provider metadata
parent
09d8d842
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1025 additions
and
31 deletions
+1025
-31
Godeps.json
Godeps/Godeps.json
+5
-5
jose.go
Godeps/_workspace/src/github.com/coreos/go-oidc/jose/jose.go
+51
-0
jwk.go
Godeps/_workspace/src/github.com/coreos/go-oidc/jose/jwk.go
+4
-0
oauth2.go
..._workspace/src/github.com/coreos/go-oidc/oauth2/oauth2.go
+36
-1
client.go
...s/_workspace/src/github.com/coreos/go-oidc/oidc/client.go
+507
-10
provider.go
..._workspace/src/github.com/coreos/go-oidc/oidc/provider.go
+422
-15
No files found.
Godeps/Godeps.json
View file @
e80701f4
...
...
@@ -16,23 +16,23 @@
},
{
"ImportPath"
:
"github.com/coreos/go-oidc/http"
,
"Rev"
:
"
145916abb78708694762ff359ab1e34c47c7947f
"
"Rev"
:
"
6039032c0b15517897116d333ead8edf38792437
"
},
{
"ImportPath"
:
"github.com/coreos/go-oidc/jose"
,
"Rev"
:
"
145916abb78708694762ff359ab1e34c47c7947f
"
"Rev"
:
"
6039032c0b15517897116d333ead8edf38792437
"
},
{
"ImportPath"
:
"github.com/coreos/go-oidc/key"
,
"Rev"
:
"
145916abb78708694762ff359ab1e34c47c7947f
"
"Rev"
:
"
6039032c0b15517897116d333ead8edf38792437
"
},
{
"ImportPath"
:
"github.com/coreos/go-oidc/oauth2"
,
"Rev"
:
"
145916abb78708694762ff359ab1e34c47c7947f
"
"Rev"
:
"
6039032c0b15517897116d333ead8edf38792437
"
},
{
"ImportPath"
:
"github.com/coreos/go-oidc/oidc"
,
"Rev"
:
"
145916abb78708694762ff359ab1e34c47c7947f
"
"Rev"
:
"
6039032c0b15517897116d333ead8edf38792437
"
},
{
"ImportPath"
:
"github.com/coreos/pkg/capnslog"
,
...
...
Godeps/_workspace/src/github.com/coreos/go-oidc/jose/jose.go
View file @
e80701f4
...
...
@@ -13,6 +13,57 @@ const (
HeaderKeyID
=
"kid"
)
const
(
// Encryption Algorithm Header Parameter Values for JWS
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-6
AlgHS256
=
"HS256"
AlgHS384
=
"HS384"
AlgHS512
=
"HS512"
AlgRS256
=
"RS256"
AlgRS384
=
"RS384"
AlgRS512
=
"RS512"
AlgES256
=
"ES256"
AlgES384
=
"ES384"
AlgES512
=
"ES512"
AlgPS256
=
"PS256"
AlgPS384
=
"PS384"
AlgPS512
=
"PS512"
AlgNone
=
"none"
)
const
(
// Algorithm Header Parameter Values for JWE
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-4.1
AlgRSA15
=
"RSA1_5"
AlgRSAOAEP
=
"RSA-OAEP"
AlgRSAOAEP256
=
"RSA-OAEP-256"
AlgA128KW
=
"A128KW"
AlgA192KW
=
"A192KW"
AlgA256KW
=
"A256KW"
AlgDir
=
"dir"
AlgECDHES
=
"ECDH-ES"
AlgECDHESA128KW
=
"ECDH-ES+A128KW"
AlgECDHESA192KW
=
"ECDH-ES+A192KW"
AlgECDHESA256KW
=
"ECDH-ES+A256KW"
AlgA128GCMKW
=
"A128GCMKW"
AlgA192GCMKW
=
"A192GCMKW"
AlgA256GCMKW
=
"A256GCMKW"
AlgPBES2HS256A128KW
=
"PBES2-HS256+A128KW"
AlgPBES2HS384A192KW
=
"PBES2-HS384+A192KW"
AlgPBES2HS512A256KW
=
"PBES2-HS512+A256KW"
)
const
(
// Encryption Algorithm Header Parameter Values for JWE
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-22
EncA128CBCHS256
=
"A128CBC-HS256"
EncA128CBCHS384
=
"A128CBC-HS384"
EncA256CBCHS512
=
"A256CBC-HS512"
EncA128GCM
=
"A128GCM"
EncA192GCM
=
"A192GCM"
EncA256GCM
=
"A256GCM"
)
type
JOSEHeader
map
[
string
]
string
func
(
j
JOSEHeader
)
Validate
()
error
{
...
...
Godeps/_workspace/src/github.com/coreos/go-oidc/jose/jwk.go
View file @
e80701f4
...
...
@@ -70,6 +70,10 @@ func (j *JWK) UnmarshalJSON(data []byte) error {
return
nil
}
type
JWKSet
struct
{
Keys
[]
JWK
`json:"keys"`
}
func
decodeExponent
(
e
string
)
(
int
,
error
)
{
decE
,
err
:=
decodeBase64URLPaddingOptional
(
e
)
if
err
!=
nil
{
...
...
Godeps/_workspace/src/github.com/coreos/go-oidc/oauth2/oauth2.go
View file @
e80701f4
...
...
@@ -8,14 +8,49 @@ import (
"mime"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
phttp
"github.com/coreos/go-oidc/http"
)
// ResponseTypesEqual compares two response_type values. If either
// contains a space, it is treated as an unordered list. For example,
// comparing "code id_token" and "id_token code" would evaluate to true.
func
ResponseTypesEqual
(
r1
,
r2
string
)
bool
{
if
!
strings
.
Contains
(
r1
,
" "
)
||
!
strings
.
Contains
(
r2
,
" "
)
{
// fast route, no split needed
return
r1
==
r2
}
// split, sort, and compare
r1Fields
:=
strings
.
Fields
(
r1
)
r2Fields
:=
strings
.
Fields
(
r2
)
if
len
(
r1Fields
)
!=
len
(
r2Fields
)
{
return
false
}
sort
.
Strings
(
r1Fields
)
sort
.
Strings
(
r2Fields
)
for
i
,
r1Field
:=
range
r1Fields
{
if
r1Field
!=
r2Fields
[
i
]
{
return
false
}
}
return
true
}
const
(
ResponseTypeCode
=
"code"
// OAuth2.0 response types registered by OIDC.
//
// See: https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#RegistryContents
ResponseTypeCode
=
"code"
ResponseTypeCodeIDToken
=
"code id_token"
ResponseTypeCodeIDTokenToken
=
"code id_token token"
ResponseTypeIDToken
=
"id_token"
ResponseTypeIDTokenToken
=
"id_token token"
ResponseTypeToken
=
"token"
ResponseTypeNone
=
"none"
)
const
(
...
...
Godeps/_workspace/src/github.com/coreos/go-oidc/oidc/client.go
View file @
e80701f4
package
oidc
import
(
"encoding/json"
"errors"
"fmt"
"net/http"
"net/mail"
"net/url"
"sync"
"time"
...
...
@@ -36,23 +38,518 @@ type ClientIdentity struct {
Metadata
ClientMetadata
}
type
JWAOptions
struct
{
// SigningAlg specifies an JWA alg for signing JWTs.
//
// Specifying this field implies different actions depending on the context. It may
// require objects be serialized and signed as a JWT instead of plain JSON, or
// require an existing JWT object use the specified alg.
//
// See: http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
SigningAlg
string
// EncryptionAlg, if provided, specifies that the returned or sent object be stored
// (or nested) within a JWT object and encrypted with the provided JWA alg.
EncryptionAlg
string
// EncryptionEnc specifies the JWA enc algorithm to use with EncryptionAlg. If
// EncryptionAlg is provided and EncryptionEnc is omitted, this field defaults
// to A128CBC-HS256.
//
// If EncryptionEnc is provided EncryptionAlg must also be specified.
EncryptionEnc
string
}
func
(
opt
JWAOptions
)
valid
()
error
{
if
opt
.
EncryptionEnc
!=
""
&&
opt
.
EncryptionAlg
==
""
{
return
errors
.
New
(
"encryption encoding provided with no encryption algorithm"
)
}
return
nil
}
func
(
opt
JWAOptions
)
defaults
()
JWAOptions
{
if
opt
.
EncryptionAlg
!=
""
&&
opt
.
EncryptionEnc
==
""
{
opt
.
EncryptionEnc
=
jose
.
EncA128CBCHS256
}
return
opt
}
var
(
// Ensure ClientMetadata satisfies these interfaces.
_
json
.
Marshaler
=
&
ClientMetadata
{}
_
json
.
Unmarshaler
=
&
ClientMetadata
{}
)
// ClientMetadata holds metadata that the authorization server associates
// with a client identifier. The fields range from human-facing display
// strings such as client name, to items that impact the security of the
// protocol, such as the list of valid redirect URIs.
//
// See http://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
//
// TODO: support language specific claim representations
// http://openid.net/specs/openid-connect-registration-1_0.html#LanguagesAndScripts
type
ClientMetadata
struct
{
RedirectURLs
[]
url
.
URL
RedirectURIs
[]
url
.
URL
// Required
// A list of OAuth 2.0 "response_type" values that the client wishes to restrict
// itself to. Either "code", "token", or another registered extension.
//
// If omitted, only "code" will be used.
ResponseTypes
[]
string
// A list of OAuth 2.0 grant types the client wishes to restrict itself to.
// The grant type values used by OIDC are "authorization_code", "implicit",
// and "refresh_token".
//
// If ommitted, only "authorization_code" will be used.
GrantTypes
[]
string
// "native" or "web". If omitted, "web".
ApplicationType
string
// List of email addresses.
Contacts
[]
mail
.
Address
// Name of client to be presented to the end-user.
ClientName
string
// URL that references a logo for the Client application.
LogoURI
*
url
.
URL
// URL of the home page of the Client.
ClientURI
*
url
.
URL
// Profile data policies and terms of use to be provided to the end user.
PolicyURI
*
url
.
URL
TermsOfServiceURI
*
url
.
URL
// URL to or the value of the client's JSON Web Key Set document.
JWKSURI
*
url
.
URL
JWKS
*
jose
.
JWKSet
// URL referencing a flie with a single JSON array of redirect URIs.
SectorIdentifierURI
*
url
.
URL
SubjectType
string
// Options to restrict the JWS alg and enc values used for server responses and requests.
IDTokenResponseOptions
JWAOptions
UserInfoResponseOptions
JWAOptions
RequestObjectOptions
JWAOptions
// Client requested authorization method and signing options for the token endpoint.
//
// Defaults to "client_secret_basic"
TokenEndpointAuthMethod
string
TokenEndpointAuthSigningAlg
string
// DefaultMaxAge specifies the maximum amount of time in seconds before an authorized
// user must reauthroize.
//
// If 0, no limitation is placed on the maximum.
DefaultMaxAge
int64
// RequireAuthTime specifies if the auth_time claim in the ID token is required.
RequireAuthTime
bool
// Default Authentication Context Class Reference values for authentication requests.
DefaultACRValues
[]
string
// URI that a third party can use to initiate a login by the relaying party.
//
// See: http://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin
InitiateLoginURI
*
url
.
URL
// Pre-registered request_uri values that may be cached by the server.
RequestURIs
[]
url
.
URL
}
// Defaults returns a shallow copy of ClientMetadata with default
// values replacing omitted fields.
func
(
m
ClientMetadata
)
Defaults
()
ClientMetadata
{
if
len
(
m
.
ResponseTypes
)
==
0
{
m
.
ResponseTypes
=
[]
string
{
oauth2
.
ResponseTypeCode
}
}
if
len
(
m
.
GrantTypes
)
==
0
{
m
.
GrantTypes
=
[]
string
{
oauth2
.
GrantTypeAuthCode
}
}
if
m
.
ApplicationType
==
""
{
m
.
ApplicationType
=
"web"
}
if
m
.
TokenEndpointAuthMethod
==
""
{
m
.
TokenEndpointAuthMethod
=
oauth2
.
AuthMethodClientSecretBasic
}
m
.
IDTokenResponseOptions
=
m
.
IDTokenResponseOptions
.
defaults
()
m
.
UserInfoResponseOptions
=
m
.
UserInfoResponseOptions
.
defaults
()
m
.
RequestObjectOptions
=
m
.
RequestObjectOptions
.
defaults
()
return
m
}
func
(
m
*
ClientMetadata
)
MarshalJSON
()
([]
byte
,
error
)
{
e
:=
m
.
toEncodableStruct
()
return
json
.
Marshal
(
&
e
)
}
func
(
m
*
ClientMetadata
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
e
encodableClientMetadata
if
err
:=
json
.
Unmarshal
(
data
,
&
e
);
err
!=
nil
{
return
err
}
meta
,
err
:=
e
.
toStruct
()
if
err
!=
nil
{
return
err
}
if
err
:=
meta
.
Valid
();
err
!=
nil
{
return
err
}
*
m
=
meta
return
nil
}
type
encodableClientMetadata
struct
{
RedirectURIs
[]
string
`json:"redirect_uris"`
// Required
ResponseTypes
[]
string
`json:"response_types,omitempty"`
GrantTypes
[]
string
`json:"grant_types,omitempty"`
ApplicationType
string
`json:"application_type,omitempty"`
Contacts
[]
string
`json:"contacts,omitempty"`
ClientName
string
`json:"client_name,omitempty"`
LogoURI
string
`json:"logo_uri,omitempty"`
ClientURI
string
`json:"client_uri,omitempty"`
PolicyURI
string
`json:"policy_uri,omitempty"`
TermsOfServiceURI
string
`json:"tos_uri,omitempty"`
JWKSURI
string
`json:"jwks_uri,omitempty"`
JWKS
*
jose
.
JWKSet
`json:"jwks,omitempty"`
SectorIdentifierURI
string
`json:"sector_identifier_uri,omitempty"`
SubjectType
string
`json:"subject_type,omitempty"`
IDTokenSignedResponseAlg
string
`json:"id_token_signed_response_alg,omitempty"`
IDTokenEncryptedResponseAlg
string
`json:"id_token_encrypted_response_alg,omitempty"`
IDTokenEncryptedResponseEnc
string
`json:"id_token_encrypted_response_enc,omitempty"`
UserInfoSignedResponseAlg
string
`json:"userinfo_signed_response_alg,omitempty"`
UserInfoEncryptedResponseAlg
string
`json:"userinfo_encrypted_response_alg,omitempty"`
UserInfoEncryptedResponseEnc
string
`json:"userinfo_encrypted_response_enc,omitempty"`
RequestObjectSigningAlg
string
`json:"request_object_signing_alg,omitempty"`
RequestObjectEncryptionAlg
string
`json:"request_object_encryption_alg,omitempty"`
RequestObjectEncryptionEnc
string
`json:"request_object_encryption_enc,omitempty"`
TokenEndpointAuthMethod
string
`json:"token_endpoint_auth_method,omitempty"`
TokenEndpointAuthSigningAlg
string
`json:"token_endpoint_auth_signing_alg,omitempty"`
DefaultMaxAge
int64
`json:"default_max_age,omitempty"`
RequireAuthTime
bool
`json:"require_auth_time,omitempty"`
DefaultACRValues
[]
string
`json:"default_acr_values,omitempty"`
InitiateLoginURI
string
`json:"initiate_login_uri,omitempty"`
RequestURIs
[]
string
`json:"request_uris,omitempty"`
}
func
(
c
*
encodableClientMetadata
)
toStruct
()
(
ClientMetadata
,
error
)
{
p
:=
stickyErrParser
{}
m
:=
ClientMetadata
{
RedirectURIs
:
p
.
parseURIs
(
c
.
RedirectURIs
,
"redirect_uris"
),
ResponseTypes
:
c
.
ResponseTypes
,
GrantTypes
:
c
.
GrantTypes
,
ApplicationType
:
c
.
ApplicationType
,
Contacts
:
p
.
parseEmails
(
c
.
Contacts
,
"contacts"
),
ClientName
:
c
.
ClientName
,
LogoURI
:
p
.
parseURI
(
c
.
LogoURI
,
"logo_uri"
),
ClientURI
:
p
.
parseURI
(
c
.
ClientURI
,
"client_uri"
),
PolicyURI
:
p
.
parseURI
(
c
.
PolicyURI
,
"policy_uri"
),
TermsOfServiceURI
:
p
.
parseURI
(
c
.
TermsOfServiceURI
,
"tos_uri"
),
JWKSURI
:
p
.
parseURI
(
c
.
JWKSURI
,
"jwks_uri"
),
JWKS
:
c
.
JWKS
,
SectorIdentifierURI
:
p
.
parseURI
(
c
.
SectorIdentifierURI
,
"sector_identifier_uri"
),
SubjectType
:
c
.
SubjectType
,
TokenEndpointAuthMethod
:
c
.
TokenEndpointAuthMethod
,
TokenEndpointAuthSigningAlg
:
c
.
TokenEndpointAuthSigningAlg
,
DefaultMaxAge
:
c
.
DefaultMaxAge
,
RequireAuthTime
:
c
.
RequireAuthTime
,
DefaultACRValues
:
c
.
DefaultACRValues
,
InitiateLoginURI
:
p
.
parseURI
(
c
.
InitiateLoginURI
,
"initiate_login_uri"
),
RequestURIs
:
p
.
parseURIs
(
c
.
RequestURIs
,
"request_uris"
),
IDTokenResponseOptions
:
JWAOptions
{
c
.
IDTokenSignedResponseAlg
,
c
.
IDTokenEncryptedResponseAlg
,
c
.
IDTokenEncryptedResponseEnc
,
},
UserInfoResponseOptions
:
JWAOptions
{
c
.
UserInfoSignedResponseAlg
,
c
.
UserInfoEncryptedResponseAlg
,
c
.
UserInfoEncryptedResponseEnc
,
},
RequestObjectOptions
:
JWAOptions
{
c
.
RequestObjectSigningAlg
,
c
.
RequestObjectEncryptionAlg
,
c
.
RequestObjectEncryptionEnc
,
},
}
if
p
.
firstErr
!=
nil
{
return
ClientMetadata
{},
p
.
firstErr
}
return
m
,
nil
}
// stickyErrParser parses URIs and email addresses. Once it encounters
// a parse error, subsequent calls become no-op.
type
stickyErrParser
struct
{
firstErr
error
}
func
(
p
*
stickyErrParser
)
parseURI
(
s
,
field
string
)
*
url
.
URL
{
if
p
.
firstErr
!=
nil
||
s
==
""
{
return
nil
}
u
,
err
:=
url
.
Parse
(
s
)
if
err
==
nil
{
if
u
.
Host
==
""
{
err
=
errors
.
New
(
"no host in URI"
)
}
else
if
u
.
Scheme
!=
"http"
&&
u
.
Scheme
!=
"https"
{
err
=
errors
.
New
(
"invalid URI scheme"
)
}
}
if
err
!=
nil
{
p
.
firstErr
=
fmt
.
Errorf
(
"failed to parse %s: %v"
,
field
,
err
)
return
nil
}
return
u
}
func
(
p
*
stickyErrParser
)
parseURIs
(
s
[]
string
,
field
string
)
[]
url
.
URL
{
if
p
.
firstErr
!=
nil
||
len
(
s
)
==
0
{
return
nil
}
uris
:=
make
([]
url
.
URL
,
len
(
s
))
for
i
,
val
:=
range
s
{
if
val
==
""
{
p
.
firstErr
=
fmt
.
Errorf
(
"invalid URI in field %s"
,
field
)
return
nil
}
uris
[
i
]
=
*
(
p
.
parseURI
(
val
,
field
))
}
return
uris
}
func
(
p
*
stickyErrParser
)
parseEmails
(
s
[]
string
,
field
string
)
[]
mail
.
Address
{
if
p
.
firstErr
!=
nil
||
len
(
s
)
==
0
{
return
nil
}
addrs
:=
make
([]
mail
.
Address
,
len
(
s
))
for
i
,
addr
:=
range
s
{
if
addr
==
""
{
p
.
firstErr
=
fmt
.
Errorf
(
"invalid email in field %s"
,
field
)
return
nil
}
a
,
err
:=
mail
.
ParseAddress
(
addr
)
if
err
!=
nil
{
p
.
firstErr
=
fmt
.
Errorf
(
"invalid email in field %s: %v"
,
field
,
err
)
return
nil
}
addrs
[
i
]
=
*
a
}
return
addrs
}
func
(
m
*
ClientMetadata
)
toEncodableStruct
()
encodableClientMetadata
{
return
encodableClientMetadata
{
RedirectURIs
:
urisToStrings
(
m
.
RedirectURIs
),
ResponseTypes
:
m
.
ResponseTypes
,
GrantTypes
:
m
.
GrantTypes
,
ApplicationType
:
m
.
ApplicationType
,
Contacts
:
emailsToStrings
(
m
.
Contacts
),
ClientName
:
m
.
ClientName
,
LogoURI
:
uriToString
(
m
.
LogoURI
),
ClientURI
:
uriToString
(
m
.
ClientURI
),
PolicyURI
:
uriToString
(
m
.
PolicyURI
),
TermsOfServiceURI
:
uriToString
(
m
.
TermsOfServiceURI
),
JWKSURI
:
uriToString
(
m
.
JWKSURI
),
JWKS
:
m
.
JWKS
,
SectorIdentifierURI
:
uriToString
(
m
.
SectorIdentifierURI
),
SubjectType
:
m
.
SubjectType
,
IDTokenSignedResponseAlg
:
m
.
IDTokenResponseOptions
.
SigningAlg
,
IDTokenEncryptedResponseAlg
:
m
.
IDTokenResponseOptions
.
EncryptionAlg
,
IDTokenEncryptedResponseEnc
:
m
.
IDTokenResponseOptions
.
EncryptionEnc
,
UserInfoSignedResponseAlg
:
m
.
UserInfoResponseOptions
.
SigningAlg
,
UserInfoEncryptedResponseAlg
:
m
.
UserInfoResponseOptions
.
EncryptionAlg
,
UserInfoEncryptedResponseEnc
:
m
.
UserInfoResponseOptions
.
EncryptionEnc
,
RequestObjectSigningAlg
:
m
.
RequestObjectOptions
.
SigningAlg
,
RequestObjectEncryptionAlg
:
m
.
RequestObjectOptions
.
EncryptionAlg
,
RequestObjectEncryptionEnc
:
m
.
RequestObjectOptions
.
EncryptionEnc
,
TokenEndpointAuthMethod
:
m
.
TokenEndpointAuthMethod
,
TokenEndpointAuthSigningAlg
:
m
.
TokenEndpointAuthSigningAlg
,
DefaultMaxAge
:
m
.
DefaultMaxAge
,
RequireAuthTime
:
m
.
RequireAuthTime
,
DefaultACRValues
:
m
.
DefaultACRValues
,
InitiateLoginURI
:
uriToString
(
m
.
InitiateLoginURI
),
RequestURIs
:
urisToStrings
(
m
.
RequestURIs
),
}
}
func
uriToString
(
u
*
url
.
URL
)
string
{
if
u
==
nil
{
return
""
}
return
u
.
String
()
}
func
urisToStrings
(
urls
[]
url
.
URL
)
[]
string
{
if
len
(
urls
)
==
0
{
return
nil
}
sli
:=
make
([]
string
,
len
(
urls
))
for
i
,
u
:=
range
urls
{
sli
[
i
]
=
u
.
String
()
}
return
sli
}
func
emailsToStrings
(
addrs
[]
mail
.
Address
)
[]
string
{
if
len
(
addrs
)
==
0
{
return
nil
}
sli
:=
make
([]
string
,
len
(
addrs
))
for
i
,
addr
:=
range
addrs
{
sli
[
i
]
=
addr
.
String
()
}
return
sli
}
// Valid determines if a ClientMetadata conforms with the OIDC specification.
//
// Valid is called by UnmarshalJSON.
//
// NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
// URLs fields where the OIDC spec requires it. This may change in future releases
// of this package. See: https://github.com/coreos/go-oidc/issues/34
func
(
m
*
ClientMetadata
)
Valid
()
error
{
if
len
(
m
.
RedirectUR
L
s
)
==
0
{
if
len
(
m
.
RedirectUR
I
s
)
==
0
{
return
errors
.
New
(
"zero redirect URLs"
)
}
for
_
,
u
:=
range
m
.
RedirectURLs
{
validURI
:=
func
(
u
*
url
.
URL
,
fieldName
string
)
error
{
if
u
.
Host
==
""
{
return
fmt
.
Errorf
(
"no host for uri field %s"
,
fieldName
)
}
if
u
.
Scheme
!=
"http"
&&
u
.
Scheme
!=
"https"
{
return
errors
.
New
(
"invalid redirect URL: scheme not http/https"
)
}
else
if
u
.
Host
==
""
{
return
errors
.
New
(
"invalid redirect URL: host empty"
)
return
fmt
.
Errorf
(
"uri field %s scheme is not http or https"
,
fieldName
)
}
return
nil
}
uris
:=
[]
struct
{
val
*
url
.
URL
name
string
}{
{
m
.
LogoURI
,
"logo_uri"
},
{
m
.
ClientURI
,
"client_uri"
},
{
m
.
PolicyURI
,
"policy_uri"
},
{
m
.
TermsOfServiceURI
,
"tos_uri"
},
{
m
.
JWKSURI
,
"jwks_uri"
},
{
m
.
SectorIdentifierURI
,
"sector_identifier_uri"
},
{
m
.
InitiateLoginURI
,
"initiate_login_uri"
},
}
for
_
,
uri
:=
range
uris
{
if
uri
.
val
==
nil
{
continue
}
if
err
:=
validURI
(
uri
.
val
,
uri
.
name
);
err
!=
nil
{
return
err
}
}
uriLists
:=
[]
struct
{
vals
[]
url
.
URL
name
string
}{
{
m
.
RedirectURIs
,
"redirect_uris"
},
{
m
.
RequestURIs
,
"request_uris"
},
}
for
_
,
list
:=
range
uriLists
{
for
_
,
uri
:=
range
list
.
vals
{
if
err
:=
validURI
(
&
uri
,
list
.
name
);
err
!=
nil
{
return
err
}
}
}
options
:=
[]
struct
{
option
JWAOptions
name
string
}{
{
m
.
IDTokenResponseOptions
,
"id_token response"
},
{
m
.
UserInfoResponseOptions
,
"userinfo response"
},
{
m
.
RequestObjectOptions
,
"request_object"
},
}
for
_
,
option
:=
range
options
{
if
err
:=
option
.
option
.
valid
();
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid JWA values for %s: %v"
,
option
.
name
,
err
)
}
}
return
nil
}
type
ClientRegistrationResponse
struct
{
ClientID
string
// Required
ClientSecret
string
RegistrationAccessToken
string
RegistrationClientURI
string
// If IsZero is true, unspecified.
ClientIDIssuedAt
time
.
Time
// Time at which the client_secret will expire.
// If IsZero is true, it will not expire.
ClientSecretExpiresAt
time
.
Time
ClientMetadata
}
type
encodableClientRegistrationResponse
struct
{
ClientID
string
`json:"client_id"`
// Required
ClientSecret
string
`json:"client_secret,omitempty"`
RegistrationAccessToken
string
`json:"registration_access_token,omitempty"`
RegistrationClientURI
string
`json:"registration_client_uri,omitempty"`
ClientIDIssuedAt
int64
`json:"client_id_issued_at,omitempty"`
// Time at which the client_secret will expire, in seconds since the epoch.
// If 0 it will not expire.
ClientSecretExpiresAt
int64
`json:"client_secret_expires_at"`
// Required
encodableClientMetadata
}
func
unixToSec
(
t
time
.
Time
)
int64
{
if
t
.
IsZero
()
{
return
0
}
return
t
.
Unix
()
}
func
(
c
*
ClientRegistrationResponse
)
MarshalJSON
()
([]
byte
,
error
)
{
e
:=
encodableClientRegistrationResponse
{
ClientID
:
c
.
ClientID
,
ClientSecret
:
c
.
ClientSecret
,
RegistrationAccessToken
:
c
.
RegistrationAccessToken
,
RegistrationClientURI
:
c
.
RegistrationClientURI
,
ClientIDIssuedAt
:
unixToSec
(
c
.
ClientIDIssuedAt
),
ClientSecretExpiresAt
:
unixToSec
(
c
.
ClientSecretExpiresAt
),
encodableClientMetadata
:
c
.
ClientMetadata
.
toEncodableStruct
(),
}
return
json
.
Marshal
(
&
e
)
}
func
secToUnix
(
sec
int64
)
time
.
Time
{
if
sec
==
0
{
return
time
.
Time
{}
}
return
time
.
Unix
(
sec
,
0
)
}
func
(
c
*
ClientRegistrationResponse
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
e
encodableClientRegistrationResponse
if
err
:=
json
.
Unmarshal
(
data
,
&
e
);
err
!=
nil
{
return
err
}
if
e
.
ClientID
==
""
{
return
errors
.
New
(
"no client_id in client registration response"
)
}
metadata
,
err
:=
e
.
encodableClientMetadata
.
toStruct
()
if
err
!=
nil
{
return
err
}
*
c
=
ClientRegistrationResponse
{
ClientID
:
e
.
ClientID
,
ClientSecret
:
e
.
ClientSecret
,
RegistrationAccessToken
:
e
.
RegistrationAccessToken
,
RegistrationClientURI
:
e
.
RegistrationClientURI
,
ClientIDIssuedAt
:
secToUnix
(
e
.
ClientIDIssuedAt
),
ClientSecretExpiresAt
:
secToUnix
(
e
.
ClientSecretExpiresAt
),
ClientMetadata
:
metadata
,
}
return
nil
}
...
...
@@ -133,8 +630,8 @@ func (c *Client) OAuthClient() (*oauth2.Client, error) {
ocfg
:=
oauth2
.
Config
{
Credentials
:
oauth2
.
ClientCredentials
(
c
.
credentials
),
RedirectURL
:
c
.
redirectURL
,
AuthURL
:
cfg
.
AuthEndpoint
,
TokenURL
:
cfg
.
TokenEndpoint
,
AuthURL
:
cfg
.
AuthEndpoint
.
String
()
,
TokenURL
:
cfg
.
TokenEndpoint
.
String
()
,
Scope
:
c
.
scope
,
AuthMethod
:
authMethod
,
}
...
...
@@ -186,7 +683,7 @@ func (c *Client) maybeSyncKeys() error {
}
cfg
:=
c
.
providerConfig
.
Get
()
r
:=
NewRemotePublicKeyRepo
(
c
.
httpClient
,
cfg
.
KeysEndpoint
)
r
:=
NewRemotePublicKeyRepo
(
c
.
httpClient
,
cfg
.
KeysEndpoint
.
String
()
)
w
:=
&
clientKeyRepo
{
client
:
c
}
_
,
err
:=
key
.
Sync
(
r
,
w
)
c
.
lastKeySetSync
=
time
.
Now
()
.
UTC
()
...
...
@@ -281,7 +778,7 @@ func (c *Client) VerifyJWT(jwt jose.JWT) error {
}
v
:=
NewJWTVerifier
(
c
.
providerConfig
.
Get
()
.
Issuer
,
c
.
providerConfig
.
Get
()
.
Issuer
.
String
()
,
c
.
credentials
.
ID
,
c
.
maybeSyncKeys
,
keysFunc
)
...
...
Godeps/_workspace/src/github.com/coreos/go-oidc/oidc/provider.go
View file @
e80701f4
...
...
@@ -2,8 +2,10 @@ package oidc
import
(
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"sync"
"time"
...
...
@@ -19,6 +21,26 @@ var (
log
=
capnslog
.
NewPackageLogger
(
"github.com/coreos/go-oidc"
,
"http"
)
)
const
(
// Subject Identifier types defined by the OIDC spec. Specifies if the provider
// should provide the same sub claim value to all clients (public) or a unique
// value for each client (pairwise).
//
// See: http://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
SubjectTypePublic
=
"public"
SubjectTypePairwise
=
"pairwise"
)
var
(
// Default values for omitted provider config fields.
//
// Use ProviderConfig's Defaults method to fill a provider config with these values.
DefaultGrantTypesSupported
=
[]
string
{
oauth2
.
GrantTypeAuthCode
,
oauth2
.
GrantTypeImplicit
}
DefaultResponseModesSupported
=
[]
string
{
"query"
,
"fragment"
}
DefaultTokenEndpointAuthMethodsSupported
=
[]
string
{
oauth2
.
AuthMethodClientSecretBasic
}
DefaultClaimTypesSupported
=
[]
string
{
"normal"
}
)
const
(
MaximumProviderConfigSyncInterval
=
24
*
time
.
Hour
MinimumProviderConfigSyncInterval
=
time
.
Minute
...
...
@@ -29,29 +51,414 @@ const (
// internally configurable for tests
var
minimumProviderConfigSyncInterval
=
MinimumProviderConfigSyncInterval
var
(
// Ensure ProviderConfig satisfies these interfaces.
_
json
.
Marshaler
=
&
ProviderConfig
{}
_
json
.
Unmarshaler
=
&
ProviderConfig
{}
)
// ProviderConfig represents the OpenID Provider Metadata specifying what
// configurations a provider supports.
//
// See: http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
type
ProviderConfig
struct
{
Issuer
string
`json:"issuer"`
AuthEndpoint
string
`json:"authorization_endpoint"`
TokenEndpoint
string
`json:"token_endpoint"`
KeysEndpoint
string
`json:"jwks_uri"`
ResponseTypesSupported
[]
string
`json:"response_types_supported"`
GrantTypesSupported
[]
string
`json:"grant_types_supported"`
SubjectTypesSupported
[]
string
`json:"subject_types_supported"`
IDTokenAlgValuesSupported
[]
string
`json:"id_token_signing_alg_values_supported"`
TokenEndpointAuthMethodsSupported
[]
string
`json:"token_endpoint_auth_methods_supported"`
ExpiresAt
time
.
Time
`json:"-"`
Issuer
*
url
.
URL
// Required
AuthEndpoint
*
url
.
URL
// Required
TokenEndpoint
*
url
.
URL
// Required if grant types other than "implicit" are supported
UserInfoEndpoint
*
url
.
URL
KeysEndpoint
*
url
.
URL
// Required
RegistrationEndpoint
*
url
.
URL
// Servers MAY choose not to advertise some supported scope values even when this
// parameter is used, although those defined in OpenID Core SHOULD be listed, if supported.
ScopesSupported
[]
string
// OAuth2.0 response types supported.
ResponseTypesSupported
[]
string
// Required
// OAuth2.0 response modes supported.
//
// If omitted, defaults to DefaultResponseModesSupported.
ResponseModesSupported
[]
string
// OAuth2.0 grant types supported.
//
// If omitted, defaults to DefaultGrantTypesSupported.
GrantTypesSupported
[]
string
ACRValuesSupported
[]
string
// SubjectTypesSupported specifies strategies for providing values for the sub claim.
SubjectTypesSupported
[]
string
// Required
// JWA signing and encryption algorith values supported for ID tokens.
IDTokenSigningAlgValues
[]
string
// Required
IDTokenEncryptionAlgValues
[]
string
IDTokenEncryptionEncValues
[]
string
// JWA signing and encryption algorith values supported for user info responses.
UserInfoSigningAlgValues
[]
string
UserInfoEncryptionAlgValues
[]
string
UserInfoEncryptionEncValues
[]
string
// JWA signing and encryption algorith values supported for request objects.
ReqObjSigningAlgValues
[]
string
ReqObjEncryptionAlgValues
[]
string
ReqObjEncryptionEncValues
[]
string
TokenEndpointAuthMethodsSupported
[]
string
TokenEndpointAuthSigningAlgValuesSupported
[]
string
DisplayValuesSupported
[]
string
ClaimTypesSupported
[]
string
ClaimsSupported
[]
string
ServiceDocs
*
url
.
URL
ClaimsLocalsSupported
[]
string
UILocalsSupported
[]
string
ClaimsParameterSupported
bool
RequestParameterSupported
bool
RequestURIParamaterSupported
bool
RequireRequestURIRegistration
bool
Policy
*
url
.
URL
TermsOfService
*
url
.
URL
// Not part of the OpenID Provider Metadata
ExpiresAt
time
.
Time
}
// Defaults returns a shallow copy of ProviderConfig with default
// values replacing omitted fields.
//
// var cfg oidc.ProviderConfig
// // Fill provider config with default values for omitted fields.
// cfg = cfg.Defaults()
//
func
(
p
ProviderConfig
)
Defaults
()
ProviderConfig
{
setDefault
:=
func
(
val
*
[]
string
,
defaultVal
[]
string
)
{
if
len
(
*
val
)
==
0
{
*
val
=
defaultVal
}
}
setDefault
(
&
p
.
GrantTypesSupported
,
DefaultGrantTypesSupported
)
setDefault
(
&
p
.
ResponseModesSupported
,
DefaultResponseModesSupported
)
setDefault
(
&
p
.
TokenEndpointAuthMethodsSupported
,
DefaultTokenEndpointAuthMethodsSupported
)
setDefault
(
&
p
.
ClaimTypesSupported
,
DefaultClaimTypesSupported
)
return
p
}
func
(
p
*
ProviderConfig
)
MarshalJSON
()
([]
byte
,
error
)
{
e
:=
p
.
toEncodableStruct
()
return
json
.
Marshal
(
&
e
)
}
func
(
p
*
ProviderConfig
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
e
encodableProviderConfig
if
err
:=
json
.
Unmarshal
(
data
,
&
e
);
err
!=
nil
{
return
err
}
conf
,
err
:=
e
.
toStruct
()
if
err
!=
nil
{
return
err
}
if
err
:=
conf
.
Valid
();
err
!=
nil
{
return
err
}
*
p
=
conf
return
nil
}
type
encodableProviderConfig
struct
{
Issuer
string
`json:"issuer"`
AuthEndpoint
string
`json:"authorization_endpoint"`
TokenEndpoint
string
`json:"token_endpoint"`
UserInfoEndpoint
string
`json:"userinfo_endpoint,omitempty"`
KeysEndpoint
string
`json:"jwks_uri"`
RegistrationEndpoint
string
`json:"registration_endpoint,omitempty"`
// Use 'omitempty' for all slices as per OIDC spec:
// "Claims that return multiple values are represented as JSON arrays.
// Claims with zero elements MUST be omitted from the response."
// http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
ScopesSupported
[]
string
`json:"scopes_supported,omitempty"`
ResponseTypesSupported
[]
string
`json:"response_types_supported,omitempty"`
ResponseModesSupported
[]
string
`json:"response_modes_supported,omitempty"`
GrantTypesSupported
[]
string
`json:"grant_types_supported,omitempty"`
ACRValuesSupported
[]
string
`json:"acr_values_supported,omitempty"`
SubjectTypesSupported
[]
string
`json:"subject_types_supported,omitempty"`
IDTokenSigningAlgValues
[]
string
`json:"id_token_signing_alg_values_supported,omitempty"`
IDTokenEncryptionAlgValues
[]
string
`json:"id_token_encryption_alg_values_supported,omitempty"`
IDTokenEncryptionEncValues
[]
string
`json:"id_token_encryption_enc_values_supported,omitempty"`
UserInfoSigningAlgValues
[]
string
`json:"userinfo_signing_alg_values_supported,omitempty"`
UserInfoEncryptionAlgValues
[]
string
`json:"userinfo_encryption_alg_values_supported,omitempty"`
UserInfoEncryptionEncValues
[]
string
`json:"userinfo_encryption_enc_values_supported,omitempty"`
ReqObjSigningAlgValues
[]
string
`json:"request_object_signing_alg_values_supported,omitempty"`
ReqObjEncryptionAlgValues
[]
string
`json:"request_object_encryption_alg_values_supported,omitempty"`
ReqObjEncryptionEncValues
[]
string
`json:"request_object_encryption_enc_values_supported,omitempty"`
TokenEndpointAuthMethodsSupported
[]
string
`json:"token_endpoint_auth_methods_supported,omitempty"`
TokenEndpointAuthSigningAlgValuesSupported
[]
string
`json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
DisplayValuesSupported
[]
string
`json:"display_values_supported,omitempty"`
ClaimTypesSupported
[]
string
`json:"claim_types_supported,omitempty"`
ClaimsSupported
[]
string
`json:"claims_supported,omitempty"`
ServiceDocs
string
`json:"service_documentation,omitempty"`
ClaimsLocalsSupported
[]
string
`json:"claims_locales_supported,omitempty"`
UILocalsSupported
[]
string
`json:"ui_locales_supported,omitempty"`
ClaimsParameterSupported
bool
`json:"claims_parameter_supported,omitempty"`
RequestParameterSupported
bool
`json:"request_parameter_supported,omitempty"`
RequestURIParamaterSupported
bool
`json:"request_uri_parameter_supported,omitempty"`
RequireRequestURIRegistration
bool
`json:"require_request_uri_registration,omitempty"`
Policy
string
`json:"op_policy_uri,omitempty"`
TermsOfService
string
`json:"op_tos_uri,omitempty"`
}
func
(
cfg
ProviderConfig
)
toEncodableStruct
()
encodableProviderConfig
{
return
encodableProviderConfig
{
Issuer
:
uriToString
(
cfg
.
Issuer
),
AuthEndpoint
:
uriToString
(
cfg
.
AuthEndpoint
),
TokenEndpoint
:
uriToString
(
cfg
.
TokenEndpoint
),
UserInfoEndpoint
:
uriToString
(
cfg
.
UserInfoEndpoint
),
KeysEndpoint
:
uriToString
(
cfg
.
KeysEndpoint
),
RegistrationEndpoint
:
uriToString
(
cfg
.
RegistrationEndpoint
),
ScopesSupported
:
cfg
.
ScopesSupported
,
ResponseTypesSupported
:
cfg
.
ResponseTypesSupported
,
ResponseModesSupported
:
cfg
.
ResponseModesSupported
,
GrantTypesSupported
:
cfg
.
GrantTypesSupported
,
ACRValuesSupported
:
cfg
.
ACRValuesSupported
,
SubjectTypesSupported
:
cfg
.
SubjectTypesSupported
,
IDTokenSigningAlgValues
:
cfg
.
IDTokenSigningAlgValues
,
IDTokenEncryptionAlgValues
:
cfg
.
IDTokenEncryptionAlgValues
,
IDTokenEncryptionEncValues
:
cfg
.
IDTokenEncryptionEncValues
,
UserInfoSigningAlgValues
:
cfg
.
UserInfoSigningAlgValues
,
UserInfoEncryptionAlgValues
:
cfg
.
UserInfoEncryptionAlgValues
,
UserInfoEncryptionEncValues
:
cfg
.
UserInfoEncryptionEncValues
,
ReqObjSigningAlgValues
:
cfg
.
ReqObjSigningAlgValues
,
ReqObjEncryptionAlgValues
:
cfg
.
ReqObjEncryptionAlgValues
,
ReqObjEncryptionEncValues
:
cfg
.
ReqObjEncryptionEncValues
,
TokenEndpointAuthMethodsSupported
:
cfg
.
TokenEndpointAuthMethodsSupported
,
TokenEndpointAuthSigningAlgValuesSupported
:
cfg
.
TokenEndpointAuthSigningAlgValuesSupported
,
DisplayValuesSupported
:
cfg
.
DisplayValuesSupported
,
ClaimTypesSupported
:
cfg
.
ClaimTypesSupported
,
ClaimsSupported
:
cfg
.
ClaimsSupported
,
ServiceDocs
:
uriToString
(
cfg
.
ServiceDocs
),
ClaimsLocalsSupported
:
cfg
.
ClaimsLocalsSupported
,
UILocalsSupported
:
cfg
.
UILocalsSupported
,
ClaimsParameterSupported
:
cfg
.
ClaimsParameterSupported
,
RequestParameterSupported
:
cfg
.
RequestParameterSupported
,
RequestURIParamaterSupported
:
cfg
.
RequestURIParamaterSupported
,
RequireRequestURIRegistration
:
cfg
.
RequireRequestURIRegistration
,
Policy
:
uriToString
(
cfg
.
Policy
),
TermsOfService
:
uriToString
(
cfg
.
TermsOfService
),
}
}
func
(
e
encodableProviderConfig
)
toStruct
()
(
ProviderConfig
,
error
)
{
p
:=
stickyErrParser
{}
conf
:=
ProviderConfig
{
Issuer
:
p
.
parseURI
(
e
.
Issuer
,
"issuer"
),
AuthEndpoint
:
p
.
parseURI
(
e
.
AuthEndpoint
,
"authorization_endpoint"
),
TokenEndpoint
:
p
.
parseURI
(
e
.
TokenEndpoint
,
"token_endpoint"
),
UserInfoEndpoint
:
p
.
parseURI
(
e
.
UserInfoEndpoint
,
"userinfo_endpoint"
),
KeysEndpoint
:
p
.
parseURI
(
e
.
KeysEndpoint
,
"jwks_uri"
),
RegistrationEndpoint
:
p
.
parseURI
(
e
.
RegistrationEndpoint
,
"registration_endpoint"
),
ScopesSupported
:
e
.
ScopesSupported
,
ResponseTypesSupported
:
e
.
ResponseTypesSupported
,
ResponseModesSupported
:
e
.
ResponseModesSupported
,
GrantTypesSupported
:
e
.
GrantTypesSupported
,
ACRValuesSupported
:
e
.
ACRValuesSupported
,
SubjectTypesSupported
:
e
.
SubjectTypesSupported
,
IDTokenSigningAlgValues
:
e
.
IDTokenSigningAlgValues
,
IDTokenEncryptionAlgValues
:
e
.
IDTokenEncryptionAlgValues
,
IDTokenEncryptionEncValues
:
e
.
IDTokenEncryptionEncValues
,
UserInfoSigningAlgValues
:
e
.
UserInfoSigningAlgValues
,
UserInfoEncryptionAlgValues
:
e
.
UserInfoEncryptionAlgValues
,
UserInfoEncryptionEncValues
:
e
.
UserInfoEncryptionEncValues
,
ReqObjSigningAlgValues
:
e
.
ReqObjSigningAlgValues
,
ReqObjEncryptionAlgValues
:
e
.
ReqObjEncryptionAlgValues
,
ReqObjEncryptionEncValues
:
e
.
ReqObjEncryptionEncValues
,
TokenEndpointAuthMethodsSupported
:
e
.
TokenEndpointAuthMethodsSupported
,
TokenEndpointAuthSigningAlgValuesSupported
:
e
.
TokenEndpointAuthSigningAlgValuesSupported
,
DisplayValuesSupported
:
e
.
DisplayValuesSupported
,
ClaimTypesSupported
:
e
.
ClaimTypesSupported
,
ClaimsSupported
:
e
.
ClaimsSupported
,
ServiceDocs
:
p
.
parseURI
(
e
.
ServiceDocs
,
"service_documentation"
),
ClaimsLocalsSupported
:
e
.
ClaimsLocalsSupported
,
UILocalsSupported
:
e
.
UILocalsSupported
,
ClaimsParameterSupported
:
e
.
ClaimsParameterSupported
,
RequestParameterSupported
:
e
.
RequestParameterSupported
,
RequestURIParamaterSupported
:
e
.
RequestURIParamaterSupported
,
RequireRequestURIRegistration
:
e
.
RequireRequestURIRegistration
,
Policy
:
p
.
parseURI
(
e
.
Policy
,
"op_policy-uri"
),
TermsOfService
:
p
.
parseURI
(
e
.
TermsOfService
,
"op_tos_uri"
),
}
if
p
.
firstErr
!=
nil
{
return
ProviderConfig
{},
p
.
firstErr
}
return
conf
,
nil
}
// Empty returns if a ProviderConfig holds no information.
//
// This case generally indicates a ProviderConfigGetter has experienced an error
// and has nothing to report.
func
(
p
ProviderConfig
)
Empty
()
bool
{
return
p
.
Issuer
==
""
return
p
.
Issuer
==
nil
}
func
contains
(
sli
[]
string
,
ele
string
)
bool
{
for
_
,
s
:=
range
sli
{
if
s
==
ele
{
return
true
}
}
return
false
}
// Valid determines if a ProviderConfig conforms with the OIDC specification.
// If Valid returns successfully it guarantees required field are non-nil and
// URLs are well formed.
//
// Valid is called by UnmarshalJSON.
//
// NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
// URLs fields where the OIDC spec requires it. This may change in future releases
// of this package. See: https://github.com/coreos/go-oidc/issues/34
func
(
p
ProviderConfig
)
Valid
()
error
{
grantTypes
:=
p
.
GrantTypesSupported
if
len
(
grantTypes
)
==
0
{
grantTypes
=
DefaultGrantTypesSupported
}
implicitOnly
:=
true
for
_
,
grantType
:=
range
grantTypes
{
if
grantType
!=
oauth2
.
GrantTypeImplicit
{
implicitOnly
=
false
break
}
}
if
len
(
p
.
SubjectTypesSupported
)
==
0
{
return
errors
.
New
(
"missing required field subject_types_supported"
)
}
if
len
(
p
.
IDTokenSigningAlgValues
)
==
0
{
return
errors
.
New
(
"missing required field id_token_signing_alg_values_supported"
)
}
if
len
(
p
.
ScopesSupported
)
!=
0
&&
!
contains
(
p
.
ScopesSupported
,
"openid"
)
{
return
errors
.
New
(
"scoped_supported must be unspecified or include 'openid'"
)
}
if
!
contains
(
p
.
IDTokenSigningAlgValues
,
"RS256"
)
{
return
errors
.
New
(
"id_token_signing_alg_values_supported must include 'RS256'"
)
}
if
contains
(
p
.
TokenEndpointAuthMethodsSupported
,
"none"
)
{
return
errors
.
New
(
"token_endpoint_auth_signing_alg_values_supported cannot include 'none'"
)
}
uris
:=
[]
struct
{
val
*
url
.
URL
name
string
required
bool
}{
{
p
.
Issuer
,
"issuer"
,
true
},
{
p
.
AuthEndpoint
,
"authorization_endpoint"
,
true
},
{
p
.
TokenEndpoint
,
"token_endpoint"
,
!
implicitOnly
},
{
p
.
UserInfoEndpoint
,
"userinfo_endpoint"
,
false
},
{
p
.
KeysEndpoint
,
"jwks_uri"
,
true
},
{
p
.
RegistrationEndpoint
,
"registration_endpoint"
,
false
},
{
p
.
ServiceDocs
,
"service_documentation"
,
false
},
{
p
.
Policy
,
"op_policy_uri"
,
false
},
{
p
.
TermsOfService
,
"op_tos_uri"
,
false
},
}
for
_
,
uri
:=
range
uris
{
if
uri
.
val
==
nil
{
if
!
uri
.
required
{
continue
}
return
fmt
.
Errorf
(
"empty value for required uri field %s"
,
uri
.
name
)
}
if
uri
.
val
.
Host
==
""
{
return
fmt
.
Errorf
(
"no host for uri field %s"
,
uri
.
name
)
}
if
uri
.
val
.
Scheme
!=
"http"
&&
uri
.
val
.
Scheme
!=
"https"
{
return
fmt
.
Errorf
(
"uri field %s schemeis not http or https"
,
uri
.
name
)
}
}
return
nil
}
// Supports determines if provider supports a client given their respective metadata.
func
(
p
ProviderConfig
)
Supports
(
c
ClientMetadata
)
error
{
if
err
:=
p
.
Valid
();
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid provider config: %v"
,
err
)
}
if
err
:=
c
.
Valid
();
err
!=
nil
{
return
fmt
.
Errorf
(
"invalid client config: %v"
,
err
)
}
// Fill default values for omitted fields
c
=
c
.
Defaults
()
p
=
p
.
Defaults
()
// Do the supported values list the requested one?
supports
:=
[]
struct
{
supported
[]
string
requested
string
name
string
}{
{
p
.
IDTokenSigningAlgValues
,
c
.
IDTokenResponseOptions
.
SigningAlg
,
"id_token_signed_response_alg"
},
{
p
.
IDTokenEncryptionAlgValues
,
c
.
IDTokenResponseOptions
.
EncryptionAlg
,
"id_token_encryption_response_alg"
},
{
p
.
IDTokenEncryptionEncValues
,
c
.
IDTokenResponseOptions
.
EncryptionEnc
,
"id_token_encryption_response_enc"
},
{
p
.
UserInfoSigningAlgValues
,
c
.
UserInfoResponseOptions
.
SigningAlg
,
"userinfo_signed_response_alg"
},
{
p
.
UserInfoEncryptionAlgValues
,
c
.
UserInfoResponseOptions
.
EncryptionAlg
,
"userinfo_encryption_response_alg"
},
{
p
.
UserInfoEncryptionEncValues
,
c
.
UserInfoResponseOptions
.
EncryptionEnc
,
"userinfo_encryption_response_enc"
},
{
p
.
ReqObjSigningAlgValues
,
c
.
RequestObjectOptions
.
SigningAlg
,
"request_object_signing_alg"
},
{
p
.
ReqObjEncryptionAlgValues
,
c
.
RequestObjectOptions
.
EncryptionAlg
,
"request_object_encryption_alg"
},
{
p
.
ReqObjEncryptionEncValues
,
c
.
RequestObjectOptions
.
EncryptionEnc
,
"request_object_encryption_enc"
},
}
for
_
,
field
:=
range
supports
{
if
field
.
requested
==
""
{
continue
}
if
!
contains
(
field
.
supported
,
field
.
requested
)
{
return
fmt
.
Errorf
(
"provider does not support requested value for field %s"
,
field
.
name
)
}
}
stringsEqual
:=
func
(
s1
,
s2
string
)
bool
{
return
s1
==
s2
}
// For lists, are the list of requested values a subset of the supported ones?
supportsAll
:=
[]
struct
{
supported
[]
string
requested
[]
string
name
string
// OAuth2.0 response_type can be space separated lists where order doesn't matter.
// For example "id_token token" is the same as "token id_token"
// Support a custom compare method.
comp
func
(
s1
,
s2
string
)
bool
}{
{
p
.
GrantTypesSupported
,
c
.
GrantTypes
,
"grant_types"
,
stringsEqual
},
{
p
.
ResponseTypesSupported
,
c
.
ResponseTypes
,
"response_type"
,
oauth2
.
ResponseTypesEqual
},
}
for
_
,
field
:=
range
supportsAll
{
requestLoop
:
for
_
,
req
:=
range
field
.
requested
{
for
_
,
sup
:=
range
field
.
supported
{
if
field
.
comp
(
req
,
sup
)
{
continue
requestLoop
}
}
return
fmt
.
Errorf
(
"provider does not support requested value for field %s"
,
field
.
name
)
}
}
// TODO(ericchiang): Are there more checks we feel comfortable with begin strict about?
return
nil
}
func
(
p
ProviderConfig
)
SupportsGrantType
(
grantType
string
)
bool
{
var
supported
[]
string
if
len
(
p
.
GrantTypesSupported
)
==
0
{
// If omitted, the default value is ["authorization_code", "implicit"].
// http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
supported
=
[]
string
{
oauth2
.
GrantTypeAuthCode
,
oauth2
.
GrantTypeImplicit
}
supported
=
DefaultGrantTypesSupported
}
else
{
supported
=
p
.
GrantTypesSupported
}
...
...
@@ -237,7 +644,7 @@ func (r *httpProviderConfigGetter) Get() (cfg ProviderConfig, err error) {
// The issuer value returned MUST be identical to the Issuer URL that was directly used to retrieve the configuration information.
// http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationValidation
if
!
urlEqual
(
cfg
.
Issuer
,
r
.
issuerURL
)
{
if
!
urlEqual
(
cfg
.
Issuer
.
String
()
,
r
.
issuerURL
)
{
err
=
fmt
.
Errorf
(
`"issuer" in config (%v) does not match provided issuer URL (%v)`
,
cfg
.
Issuer
,
r
.
issuerURL
)
return
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment