aboutsummaryrefslogtreecommitdiffstats
path: root/kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go
diff options
context:
space:
mode:
Diffstat (limited to 'kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go')
-rw-r--r--kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go188
1 files changed, 188 insertions, 0 deletions
diff --git a/kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go b/kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go
new file mode 100644
index 0000000..0024130
--- /dev/null
+++ b/kube2msb/src/kube2msb/vendor/github.com/coreos/go-oidc/oidc/verification.go
@@ -0,0 +1,188 @@
+package oidc
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/jonboulle/clockwork"
+
+ "github.com/coreos/go-oidc/jose"
+ "github.com/coreos/go-oidc/key"
+)
+
+func VerifySignature(jwt jose.JWT, keys []key.PublicKey) (bool, error) {
+ jwtBytes := []byte(jwt.Data())
+ for _, k := range keys {
+ v, err := k.Verifier()
+ if err != nil {
+ return false, err
+ }
+ if v.Verify(jwt.Signature, jwtBytes) == nil {
+ return true, nil
+ }
+ }
+ return false, nil
+}
+
+// containsString returns true if the given string(needle) is found
+// in the string array(haystack).
+func containsString(needle string, haystack []string) bool {
+ for _, v := range haystack {
+ if v == needle {
+ return true
+ }
+ }
+ return false
+}
+
+// Verify claims in accordance with OIDC spec
+// http://openid.net/specs/openid-connect-basic-1_0.html#IDTokenValidation
+func VerifyClaims(jwt jose.JWT, issuer, clientID string) error {
+ now := time.Now().UTC()
+
+ claims, err := jwt.Claims()
+ if err != nil {
+ return err
+ }
+
+ ident, err := IdentityFromClaims(claims)
+ if err != nil {
+ return err
+ }
+
+ if ident.ExpiresAt.Before(now) {
+ return errors.New("token is expired")
+ }
+
+ // iss REQUIRED. Issuer Identifier for the Issuer of the response.
+ // The iss value is a case sensitive URL using the https scheme that contains scheme,
+ // host, and optionally, port number and path components and no query or fragment components.
+ if iss, exists := claims["iss"].(string); exists {
+ if !urlEqual(iss, issuer) {
+ return fmt.Errorf("invalid claim value: 'iss'. expected=%s, found=%s.", issuer, iss)
+ }
+ } else {
+ return errors.New("missing claim: 'iss'")
+ }
+
+ // iat REQUIRED. Time at which the JWT was issued.
+ // 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.
+ if _, exists := claims["iat"].(float64); !exists {
+ return errors.New("missing claim: 'iat'")
+ }
+
+ // aud REQUIRED. Audience(s) that this ID Token is intended for.
+ // It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value.
+ // It MAY also contain identifiers for other audiences. In the general case, the aud
+ // value is an array of case sensitive strings. In the common special case when there
+ // is one audience, the aud value MAY be a single case sensitive string.
+ if aud, ok, err := claims.StringClaim("aud"); err == nil && ok {
+ if aud != clientID {
+ return fmt.Errorf("invalid claims, 'aud' claim and 'client_id' do not match, aud=%s, client_id=%s", aud, clientID)
+ }
+ } else if aud, ok, err := claims.StringsClaim("aud"); err == nil && ok {
+ if !containsString(clientID, aud) {
+ return fmt.Errorf("invalid claims, cannot find 'client_id' in 'aud' claim, aud=%v, client_id=%s", aud, clientID)
+ }
+ } else {
+ return errors.New("invalid claim value: 'aud' is required, and should be either string or string array")
+ }
+
+ return nil
+}
+
+// VerifyClientClaims verifies all the required claims are valid for a "client credentials" JWT.
+// Returns the client ID if valid, or an error if invalid.
+func VerifyClientClaims(jwt jose.JWT, issuer string) (string, error) {
+ claims, err := jwt.Claims()
+ if err != nil {
+ return "", fmt.Errorf("failed to parse JWT claims: %v", err)
+ }
+
+ iss, ok, err := claims.StringClaim("iss")
+ if err != nil {
+ return "", fmt.Errorf("failed to parse 'iss' claim: %v", err)
+ } else if !ok {
+ return "", errors.New("missing required 'iss' claim")
+ } else if !urlEqual(iss, issuer) {
+ return "", fmt.Errorf("'iss' claim does not match expected issuer, iss=%s", iss)
+ }
+
+ sub, ok, err := claims.StringClaim("sub")
+ if err != nil {
+ return "", fmt.Errorf("failed to parse 'sub' claim: %v", err)
+ } else if !ok {
+ return "", errors.New("missing required 'sub' claim")
+ }
+
+ if aud, ok, err := claims.StringClaim("aud"); err == nil && ok {
+ if aud != sub {
+ return "", fmt.Errorf("invalid claims, 'aud' claim and 'sub' claim do not match, aud=%s, sub=%s", aud, sub)
+ }
+ } else if aud, ok, err := claims.StringsClaim("aud"); err == nil && ok {
+ if !containsString(sub, aud) {
+ return "", fmt.Errorf("invalid claims, cannot find 'sud' in 'aud' claim, aud=%v, sub=%s", aud, sub)
+ }
+ } else {
+ return "", errors.New("invalid claim value: 'aud' is required, and should be either string or string array")
+ }
+
+ now := time.Now().UTC()
+ exp, ok, err := claims.TimeClaim("exp")
+ if err != nil {
+ return "", fmt.Errorf("failed to parse 'exp' claim: %v", err)
+ } else if !ok {
+ return "", errors.New("missing required 'exp' claim")
+ } else if exp.Before(now) {
+ return "", fmt.Errorf("token already expired at: %v", exp)
+ }
+
+ return sub, nil
+}
+
+type JWTVerifier struct {
+ issuer string
+ clientID string
+ syncFunc func() error
+ keysFunc func() []key.PublicKey
+ clock clockwork.Clock
+}
+
+func NewJWTVerifier(issuer, clientID string, syncFunc func() error, keysFunc func() []key.PublicKey) JWTVerifier {
+ return JWTVerifier{
+ issuer: issuer,
+ clientID: clientID,
+ syncFunc: syncFunc,
+ keysFunc: keysFunc,
+ clock: clockwork.NewRealClock(),
+ }
+}
+
+func (v *JWTVerifier) Verify(jwt jose.JWT) error {
+ ok, err := VerifySignature(jwt, v.keysFunc())
+ if ok {
+ goto SignatureVerified
+ } else if err != nil {
+ return fmt.Errorf("oidc: JWT signature verification failed: %v", err)
+ }
+
+ if err = v.syncFunc(); err != nil {
+ return fmt.Errorf("oidc: failed syncing KeySet: %v", err)
+ }
+
+ ok, err = VerifySignature(jwt, v.keysFunc())
+ if err != nil {
+ return fmt.Errorf("oidc: JWT signature verification failed: %v", err)
+ } else if !ok {
+ return errors.New("oidc: unable to verify JWT signature: no matching keys")
+ }
+
+SignatureVerified:
+ if err := VerifyClaims(jwt, v.issuer, v.clientID); err != nil {
+ return fmt.Errorf("oidc: JWT claims invalid: %v", err)
+ }
+
+ return nil
+}