Merge branch 'master' of github.com:caos/oidc
This commit is contained in:
commit
d7befc087d
11 changed files with 49 additions and 35 deletions
|
@ -140,6 +140,9 @@ func (s *AuthStorage) AuthRequestByID(_ context.Context, id string) (op.AuthRequ
|
||||||
}
|
}
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
func (s *AuthStorage) CreateToken(_ context.Context, authReq op.AuthRequest) (string, time.Time, error) {
|
||||||
|
return authReq.GetID(), time.Now().UTC().Add(5 * time.Minute), nil
|
||||||
|
}
|
||||||
func (s *AuthStorage) GetSigningKey(_ context.Context, keyCh chan<- jose.SigningKey, _ chan<- error, _ <-chan time.Time) {
|
func (s *AuthStorage) GetSigningKey(_ context.Context, keyCh chan<- jose.SigningKey, _ chan<- error, _ <-chan time.Time) {
|
||||||
keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: s.key}
|
keyCh <- jose.SigningKey{Algorithm: jose.RS256, Key: s.key}
|
||||||
}
|
}
|
||||||
|
@ -243,9 +246,6 @@ func (c *ConfClient) GetAuthMethod() op.AuthMethod {
|
||||||
return c.authMethod
|
return c.authMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfClient) AccessTokenLifetime() time.Duration {
|
|
||||||
return time.Duration(5 * time.Minute)
|
|
||||||
}
|
|
||||||
func (c *ConfClient) IDTokenLifetime() time.Duration {
|
func (c *ConfClient) IDTokenLifetime() time.Duration {
|
||||||
return time.Duration(5 * time.Minute)
|
return time.Duration(5 * time.Minute)
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/golang/mock v1.3.1
|
github.com/golang/mock v1.3.1
|
||||||
github.com/golang/protobuf v1.3.2 // indirect
|
github.com/golang/protobuf v1.3.2 // indirect
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/gorilla/handlers v1.4.2
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/schema v1.1.0
|
github.com/gorilla/schema v1.1.0
|
||||||
github.com/gorilla/securecookie v1.1.1
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -12,6 +12,8 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||||
|
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
|
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
|
||||||
|
@ -54,8 +56,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM=
|
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM=
|
||||||
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -74,7 +74,5 @@ gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A
|
||||||
gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
|
@ -179,7 +179,7 @@ func AuthResponseCode(w http.ResponseWriter, r *http.Request, authReq AuthReques
|
||||||
|
|
||||||
func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer, client Client) {
|
func AuthResponseToken(w http.ResponseWriter, r *http.Request, authReq AuthRequest, authorizer Authorizer, client Client) {
|
||||||
createAccessToken := authReq.GetResponseType() != oidc.ResponseTypeIDTokenOnly
|
createAccessToken := authReq.GetResponseType() != oidc.ResponseTypeIDTokenOnly
|
||||||
resp, err := CreateTokenResponse(authReq, client, authorizer, createAccessToken, "")
|
resp, err := CreateTokenResponse(r.Context(), authReq, client, authorizer, createAccessToken, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AuthRequestError(w, r, authReq, err, authorizer.Encoder())
|
AuthRequestError(w, r, authReq, err, authorizer.Encoder())
|
||||||
return
|
return
|
||||||
|
|
|
@ -18,7 +18,6 @@ type Client interface {
|
||||||
GetAuthMethod() AuthMethod
|
GetAuthMethod() AuthMethod
|
||||||
LoginURL(string) string
|
LoginURL(string) string
|
||||||
AccessTokenType() AccessTokenType
|
AccessTokenType() AccessTokenType
|
||||||
AccessTokenLifetime() time.Duration
|
|
||||||
IDTokenLifetime() time.Duration
|
IDTokenLifetime() time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,20 +34,6 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessTokenLifetime mocks base method
|
|
||||||
func (m *MockClient) AccessTokenLifetime() time.Duration {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "AccessTokenLifetime")
|
|
||||||
ret0, _ := ret[0].(time.Duration)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccessTokenLifetime indicates an expected call of AccessTokenLifetime
|
|
||||||
func (mr *MockClientMockRecorder) AccessTokenLifetime() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenLifetime", reflect.TypeOf((*MockClient)(nil).AccessTokenLifetime))
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccessTokenType mocks base method
|
// AccessTokenType mocks base method
|
||||||
func (m *MockClient) AccessTokenType() op.AccessTokenType {
|
func (m *MockClient) AccessTokenType() op.AccessTokenType {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -81,6 +81,22 @@ func (mr *MockStorageMockRecorder) CreateAuthRequest(arg0, arg1 interface{}) *go
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthRequest", reflect.TypeOf((*MockStorage)(nil).CreateAuthRequest), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthRequest", reflect.TypeOf((*MockStorage)(nil).CreateAuthRequest), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateToken mocks base method
|
||||||
|
func (m *MockStorage) CreateToken(arg0 context.Context, arg1 op.AuthRequest) (string, time.Time, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateToken", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
ret1, _ := ret[1].(time.Time)
|
||||||
|
ret2, _ := ret[2].(error)
|
||||||
|
return ret0, ret1, ret2
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateToken indicates an expected call of CreateToken
|
||||||
|
func (mr *MockStorageMockRecorder) CreateToken(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateToken", reflect.TypeOf((*MockStorage)(nil).CreateToken), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteAuthRequest mocks base method
|
// DeleteAuthRequest mocks base method
|
||||||
func (m *MockStorage) DeleteAuthRequest(arg0 context.Context, arg1 string) error {
|
func (m *MockStorage) DeleteAuthRequest(arg0 context.Context, arg1 string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ func CreateRouter(o OpenIDProvider, h HttpInterceptor) *mux.Router {
|
||||||
h = DefaultInterceptor
|
h = DefaultInterceptor
|
||||||
}
|
}
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
router.Use(handlers.CORS())
|
||||||
router.HandleFunc(healthzEndpoint, Healthz)
|
router.HandleFunc(healthzEndpoint, Healthz)
|
||||||
router.HandleFunc(readinessEndpoint, o.HandleReady)
|
router.HandleFunc(readinessEndpoint, o.HandleReady)
|
||||||
router.HandleFunc(oidc.DiscoveryEndpoint, o.HandleDiscovery)
|
router.HandleFunc(oidc.DiscoveryEndpoint, o.HandleDiscovery)
|
||||||
|
|
|
@ -14,6 +14,8 @@ type AuthStorage interface {
|
||||||
AuthRequestByID(context.Context, string) (AuthRequest, error)
|
AuthRequestByID(context.Context, string) (AuthRequest, error)
|
||||||
DeleteAuthRequest(context.Context, string) error
|
DeleteAuthRequest(context.Context, string) error
|
||||||
|
|
||||||
|
CreateToken(context.Context, AuthRequest) (string, time.Time, error)
|
||||||
|
|
||||||
GetSigningKey(context.Context, chan<- jose.SigningKey, chan<- error, <-chan time.Time)
|
GetSigningKey(context.Context, chan<- jose.SigningKey, chan<- error, <-chan time.Time)
|
||||||
GetKeySet(context.Context) (*jose.JSONWebKeySet, error)
|
GetKeySet(context.Context) (*jose.JSONWebKeySet, error)
|
||||||
SaveNewKeyPair(context.Context) error
|
SaveNewKeyPair(context.Context) error
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package op
|
package op
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
|
@ -13,11 +14,12 @@ type TokenCreator interface {
|
||||||
Crypto() Crypto
|
Crypto() Crypto
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateTokenResponse(authReq AuthRequest, client Client, creator TokenCreator, createAccessToken bool, code string) (*oidc.AccessTokenResponse, error) {
|
func CreateTokenResponse(ctx context.Context, authReq AuthRequest, client Client, creator TokenCreator, createAccessToken bool, code string) (*oidc.AccessTokenResponse, error) {
|
||||||
var accessToken string
|
var accessToken string
|
||||||
|
var validity time.Duration
|
||||||
if createAccessToken {
|
if createAccessToken {
|
||||||
var err error
|
var err error
|
||||||
accessToken, err = CreateAccessToken(authReq, client, creator)
|
accessToken, validity, err = CreateAccessToken(ctx, authReq, client, creator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -26,7 +28,8 @@ func CreateTokenResponse(authReq AuthRequest, client Client, creator TokenCreato
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exp := uint64(client.AccessTokenLifetime().Seconds())
|
|
||||||
|
exp := uint64(validity.Seconds())
|
||||||
return &oidc.AccessTokenResponse{
|
return &oidc.AccessTokenResponse{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
IDToken: idToken,
|
IDToken: idToken,
|
||||||
|
@ -35,21 +38,27 @@ func CreateTokenResponse(authReq AuthRequest, client Client, creator TokenCreato
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateAccessToken(authReq AuthRequest, client Client, creator TokenCreator) (string, error) {
|
func CreateAccessToken(ctx context.Context, authReq AuthRequest, client Client, creator TokenCreator) (token string, validity time.Duration, err error) {
|
||||||
if client.AccessTokenType() == AccessTokenTypeJWT {
|
id, exp, err := creator.Storage().CreateToken(ctx, authReq)
|
||||||
return CreateJWT(creator.Issuer(), authReq, client, creator.Signer())
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
}
|
}
|
||||||
return CreateBearerToken(authReq, creator.Crypto())
|
validity = exp.Sub(time.Now().UTC())
|
||||||
|
if client.AccessTokenType() == AccessTokenTypeJWT {
|
||||||
|
token, err = CreateJWT(creator.Issuer(), authReq, exp, id, creator.Signer())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err = CreateBearerToken(id, creator.Crypto())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateBearerToken(authReq AuthRequest, crypto Crypto) (string, error) {
|
func CreateBearerToken(id string, crypto Crypto) (string, error) {
|
||||||
return crypto.Encrypt(authReq.GetID())
|
return crypto.Encrypt(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateJWT(issuer string, authReq AuthRequest, client Client, signer Signer) (string, error) {
|
func CreateJWT(issuer string, authReq AuthRequest, exp time.Time, id string, signer Signer) (string, error) {
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
nbf := now
|
nbf := now
|
||||||
exp := now.Add(client.AccessTokenLifetime())
|
|
||||||
claims := &oidc.AccessTokenClaims{
|
claims := &oidc.AccessTokenClaims{
|
||||||
Issuer: issuer,
|
Issuer: issuer,
|
||||||
Subject: authReq.GetSubject(),
|
Subject: authReq.GetSubject(),
|
||||||
|
@ -57,6 +66,7 @@ func CreateJWT(issuer string, authReq AuthRequest, client Client, signer Signer)
|
||||||
Expiration: exp,
|
Expiration: exp,
|
||||||
IssuedAt: now,
|
IssuedAt: now,
|
||||||
NotBefore: nbf,
|
NotBefore: nbf,
|
||||||
|
JWTID: id,
|
||||||
}
|
}
|
||||||
return signer.SignAccessToken(claims)
|
return signer.SignAccessToken(claims)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ func CodeExchange(w http.ResponseWriter, r *http.Request, exchanger Exchanger) {
|
||||||
ExchangeRequestError(w, r, err)
|
ExchangeRequestError(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp, err := CreateTokenResponse(authReq, client, exchanger, true, tokenReq.Code)
|
resp, err := CreateTokenResponse(r.Context(), authReq, client, exchanger, true, tokenReq.Code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ExchangeRequestError(w, r, err)
|
ExchangeRequestError(w, r, err)
|
||||||
return
|
return
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue