support OIDC protocol

Signed-off-by: hongming <hongming@kubesphere.io>
This commit is contained in:
hongming
2021-09-14 18:06:28 +08:00
parent 4b5b1c64bc
commit 8c5c6a7dee
5 changed files with 199 additions and 30 deletions

View File

@@ -61,6 +61,12 @@ type VerifiedResponse struct {
Claims
}
// Keys hold encryption and signing keys.
type Keys struct {
SigningKey *jose.JSONWebKey
SigningKeyPub *jose.JSONWebKey
}
// Issuer issues token to user, tokens are required to perform mutating requests to resources
type Issuer interface {
// IssueTo issues a token a User, return error if issuing process failed
@@ -68,6 +74,9 @@ type Issuer interface {
// Verify verifies a token, and return a user info if it's a valid token, otherwise return error
Verify(string) (*VerifiedResponse, error)
// Keys hold encryption and signing keys.
Keys() *Keys
}
type Claims struct {
@@ -80,6 +89,14 @@ type Claims struct {
// String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
// The value is passed through unmodified from the Authentication Request to the ID Token.
Nonce string `json:"nonce,omitempty"`
// Scopes can be used to request that specific sets of information be made available as Claim Values.
Scopes []string `json:"scopes,omitempty"`
// End-User's preferred e-mail address.
Email string `json:"email,omitempty"`
// End-User's locale, represented as a BCP47 [RFC5646] language tag.
Locale string `json:"locale,omitempty"`
// Shorthand name by which the End-User wishes to be referred to at the RP,
PreferredUsername string `json:"preferred_username,omitempty"`
// Extra contains the additional information
Extra map[string][]string `json:"extra,omitempty"`
}
@@ -90,7 +107,7 @@ type issuer struct {
// signing access_token and refresh_token
secret []byte
// signing id_token
signKey *jose.JSONWebKey
signKey *Keys
// Token verification maximum time difference
maximumClockSkew time.Duration
}
@@ -114,6 +131,18 @@ func (s *issuer) IssueTo(request *IssueRequest) (string, error) {
if request.Nonce != "" {
claims.Nonce = request.Nonce
}
if request.Email != "" {
claims.Email = request.Email
}
if request.PreferredUsername != "" {
claims.PreferredUsername = request.PreferredUsername
}
if request.Locale != "" {
claims.Locale = request.Locale
}
if len(request.Scopes) > 0 {
claims.Scopes = request.Scopes
}
if request.ExpiresIn > 0 {
claims.ExpiresAt = claims.IssuedAt + int64(request.ExpiresIn.Seconds())
}
@@ -122,8 +151,8 @@ func (s *issuer) IssueTo(request *IssueRequest) (string, error) {
var err error
if request.TokenType == IDToken {
t := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
t.Header[headerKeyID] = s.signKey.KeyID
token, err = t.SignedString(s.signKey.Key)
t.Header[headerKeyID] = s.signKey.SigningKey.KeyID
token, err = t.SignedString(s.signKey.SigningKey.Key)
} else {
token, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(s.secret)
}
@@ -175,13 +204,17 @@ func (s *issuer) Verify(token string) (*VerifiedResponse, error) {
return verified, nil
}
func (s *issuer) Keys() *Keys {
return s.signKey
}
func (s *issuer) keyFunc(token *jwt.Token) (i interface{}, err error) {
alg, _ := token.Header[headerAlgorithm].(string)
switch alg {
case jwt.SigningMethodHS256.Alg():
return s.secret, nil
case jwt.SigningMethodRS256.Alg():
return s.signKey.Key, nil
return s.signKey.SigningKey.Key, nil
default:
return nil, fmt.Errorf("unexpect signature algorithm %v", token.Header[headerAlgorithm])
}
@@ -263,11 +296,19 @@ func NewIssuer(options *authentication.Options) (Issuer, error) {
name: options.OAuthOptions.Issuer,
secret: []byte(options.JwtSecret),
maximumClockSkew: options.MaximumClockSkew,
signKey: &jose.JSONWebKey{
Key: signKey,
KeyID: keyID,
Algorithm: jwt.SigningMethodRS256.Alg(),
Use: "sig",
signKey: &Keys{
SigningKey: &jose.JSONWebKey{
Key: signKey,
KeyID: keyID,
Algorithm: jwt.SigningMethodRS256.Alg(),
Use: "sig",
},
SigningKeyPub: &jose.JSONWebKey{
Key: signKey.Public(),
KeyID: keyID,
Algorithm: jwt.SigningMethodRS256.Alg(),
Use: "sig",
},
},
}, nil
}