impl
This commit is contained in:
parent
85b71e0867
commit
d1d04295a6
12 changed files with 383 additions and 40 deletions
|
@ -22,6 +22,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
@ -98,6 +100,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
|
|
@ -8,5 +8,38 @@ type Storage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) CreateAuthRequest(authReq *oidc.AuthRequest) error {
|
func (s *Storage) CreateAuthRequest(authReq *oidc.AuthRequest) error {
|
||||||
|
authReq.ID = "id"
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (s *Storage) GetClientByClientID(string) (oidc.Client, error) {
|
||||||
|
return &ConfClient{}, nil
|
||||||
|
}
|
||||||
|
func (s *Storage) AuthRequestByCode(oidc.Client, string, string) (*oidc.AuthRequest, error) {
|
||||||
|
return &oidc.AuthRequest{ID: "id"}, nil
|
||||||
|
}
|
||||||
|
func (s *Storage) AuthorizeClientIDSecret(string, string) (oidc.Client, error) {
|
||||||
|
return &ConfClient{}, nil
|
||||||
|
}
|
||||||
|
func (s *Storage) AuthorizeClientIDCodeVerifier(string, string) (oidc.Client, error) {
|
||||||
|
return &ConfClient{}, nil
|
||||||
|
}
|
||||||
|
func (s *Storage) DeleteAuthRequestAndCode(string, string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfClient struct{}
|
||||||
|
|
||||||
|
func (c *ConfClient) Type() oidc.ClientType {
|
||||||
|
return oidc.ClientTypeConfidential
|
||||||
|
}
|
||||||
|
func (c *ConfClient) RedirectURIs() []string {
|
||||||
|
return []string{
|
||||||
|
"https://registered.com/callback",
|
||||||
|
"http://localhost:9999/callback",
|
||||||
|
"custom://callback",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConfClient) LoginURL(id string) string {
|
||||||
|
return "login?id=" + id
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
ScopeOpenID = "openid"
|
||||||
|
|
||||||
ResponseTypeCode ResponseType = "code"
|
ResponseTypeCode ResponseType = "code"
|
||||||
ResponseTypeIDToken ResponseType = "id_token token"
|
ResponseTypeIDToken ResponseType = "id_token token"
|
||||||
ResponseTypeIDTokenOnly ResponseType = "id_token"
|
ResponseTypeIDTokenOnly ResponseType = "id_token"
|
||||||
|
@ -21,6 +23,8 @@ const (
|
||||||
PromptLogin = "login"
|
PromptLogin = "login"
|
||||||
PromptConsent = "consent"
|
PromptConsent = "consent"
|
||||||
PromptSelectAccount = "select_account"
|
PromptSelectAccount = "select_account"
|
||||||
|
|
||||||
|
GrantTypeCode GrantType = "authorization_code"
|
||||||
)
|
)
|
||||||
|
|
||||||
var displayValues = map[string]Display{
|
var displayValues = map[string]Display{
|
||||||
|
@ -34,6 +38,7 @@ var displayValues = map[string]Display{
|
||||||
//https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
//https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||||
//
|
//
|
||||||
type AuthRequest struct {
|
type AuthRequest struct {
|
||||||
|
ID string
|
||||||
Scopes Scopes `schema:"scope"`
|
Scopes Scopes `schema:"scope"`
|
||||||
ResponseType ResponseType `schema:"response_type"`
|
ResponseType ResponseType `schema:"response_type"`
|
||||||
ClientID string `schema:"client_id"`
|
ClientID string `schema:"client_id"`
|
||||||
|
@ -53,6 +58,49 @@ type AuthRequest struct {
|
||||||
ACRValues []string `schema:"acr_values"`
|
ACRValues []string `schema:"acr_values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenRequest interface {
|
||||||
|
// GrantType GrantType `schema:"grant_type"`
|
||||||
|
GrantType() GrantType
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenRequestType GrantType
|
||||||
|
|
||||||
|
type AccessTokenRequest struct {
|
||||||
|
Code string `schema:"code"`
|
||||||
|
RedirectURI string `schema:"redirect_uri"`
|
||||||
|
ClientID string `schema:"client_id"`
|
||||||
|
ClientSecret string `schema:"client_secret"`
|
||||||
|
CodeVerifier string `schema:"code_verifier"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccessTokenRequest) GrantType() GrantType {
|
||||||
|
return GrantTypeCode
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccessTokenResponse struct {
|
||||||
|
AccessToken string `json:"access_token,omitempty"`
|
||||||
|
TokenType string `json:"token_type,omitempty"`
|
||||||
|
RefreshToken string `json:"refresh_token,omitempty"`
|
||||||
|
ExpiresIn uint64 `json:"expires_in,omitempty"`
|
||||||
|
IDToken string `json:"id_token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (a AccessTokenRequest) UnmarshalText(text []byte) error {
|
||||||
|
// fmt.Println(string(text))
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
type TokenExchangeRequest struct {
|
||||||
|
subjectToken string `schema:"subject_token"`
|
||||||
|
subjectTokenType string `schema:"subject_token_type"`
|
||||||
|
actorToken string `schema:"actor_token"`
|
||||||
|
actorTokenType string `schema:"actor_token_type"`
|
||||||
|
resource []string `schema:"resource"`
|
||||||
|
audience []string `schema:"audience"`
|
||||||
|
Scope []string `schema:"scope"`
|
||||||
|
requestedTokenType string `schema:"requested_token_type"`
|
||||||
|
}
|
||||||
|
|
||||||
// func (a *AuthRequest) UnmarshalText(text []byte) error {
|
// func (a *AuthRequest) UnmarshalText(text []byte) error {
|
||||||
// // var f formAuthRequest
|
// // var f formAuthRequest
|
||||||
// log.Println(string(text))
|
// log.Println(string(text))
|
||||||
|
@ -115,3 +163,5 @@ func (l *Locales) UnmarshalText(text []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GrantType string
|
||||||
|
|
18
pkg/oidc/client.go
Normal file
18
pkg/oidc/client.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package oidc
|
||||||
|
|
||||||
|
type Client interface {
|
||||||
|
RedirectURIs() []string
|
||||||
|
Type() ClientType
|
||||||
|
LoginURL(string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientType int
|
||||||
|
|
||||||
|
func (c ClientType) IsConvidential() bool {
|
||||||
|
return c == ClientTypeConfidential
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientTypeConfidential ClientType = iota
|
||||||
|
ClientTypePublic
|
||||||
|
)
|
|
@ -10,7 +10,7 @@ import (
|
||||||
str_utils "github.com/caos/utils/strings"
|
str_utils "github.com/caos/utils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseAuthRequest(w http.ResponseWriter, r *http.Request) (*oidc.AuthRequest, error) {
|
func Authorize(w http.ResponseWriter, r *http.Request, storage Storage) (*oidc.AuthRequest, error) {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("Unimplemented") //TODO: impl
|
return nil, errors.New("Unimplemented") //TODO: impl
|
||||||
|
@ -22,25 +22,53 @@ func ParseAuthRequest(w http.ResponseWriter, r *http.Request) (*oidc.AuthRequest
|
||||||
d.IgnoreUnknownKeys(true)
|
d.IgnoreUnknownKeys(true)
|
||||||
|
|
||||||
err = d.Decode(authReq, r.Form)
|
err = d.Decode(authReq, r.Form)
|
||||||
return authReq, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = ValidateAuthRequest(authReq, storage); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = storage.CreateAuthRequest(authReq)
|
||||||
|
if err != nil {
|
||||||
|
//TODO: return err
|
||||||
|
}
|
||||||
|
client, err := storage.GetClientByClientID(authReq.ClientID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
RedirectToLogin(authReq, client, w, r)
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateAuthRequest(authRequest *oidc.AuthRequest, storage Storage) error {
|
func ValidateAuthRequest(authReq *oidc.AuthRequest, storage Storage) error {
|
||||||
|
if err := ValidateAuthReqScopes(authReq.Scopes); err != nil {
|
||||||
if err := ValidateRedirectURI(authRequest.RedirectURI, authRequest.ClientID, storage); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ValidateAuthReqRedirectURI(authReq.RedirectURI, authReq.ClientID, storage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
return errors.New("Unimplemented") //TODO: impl https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.2
|
return errors.New("Unimplemented") //TODO: impl https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.2
|
||||||
|
|
||||||
// if NeedsExistingSession(authRequest) {
|
// if NeedsExistingSession(authRequest) {
|
||||||
// session, err := storage.CheckSession(authRequest)
|
// session, err := storage.CheckSession(authRequest)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// //TODO: return err
|
// //TODO: return err<
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateRedirectURI(uri, client_id string, storage Storage) error {
|
func ValidateAuthReqScopes(scopes []string) error {
|
||||||
|
if len(scopes) == 0 {
|
||||||
|
return errors.New("scope missing")
|
||||||
|
}
|
||||||
|
if !str_utils.Contains(scopes, oidc.ScopeOpenID) {
|
||||||
|
return errors.New("scope openid missing")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateAuthReqRedirectURI(uri, client_id string, storage Storage) error {
|
||||||
if uri == "" {
|
if uri == "" {
|
||||||
return errors.New("redirect_uri must not be empty") //TODO:
|
return errors.New("redirect_uri must not be empty") //TODO:
|
||||||
}
|
}
|
||||||
|
@ -53,3 +81,8 @@ func ValidateRedirectURI(uri, client_id string, storage Storage) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RedirectToLogin(authReq *oidc.AuthRequest, client oidc.Client, w http.ResponseWriter, r *http.Request) {
|
||||||
|
login := client.LoginURL(authReq.ID)
|
||||||
|
http.Redirect(w, r, login, http.StatusFound)
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package op_test
|
package op
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -51,7 +51,7 @@ func TestValidateAuthRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := op.ValidateAuthRequest(tt.args.authRequest, tt.args.storage); (err != nil) != tt.wantErr {
|
if err := ValidateAuthRequest(tt.args.authRequest, tt.args.storage); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("ValidateAuthRequest() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("ValidateAuthRequest() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -102,7 +102,7 @@ func TestValidateRedirectURI(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := op.ValidateRedirectURI(tt.args.uri, tt.args.clientID, tt.args.storage); (err != nil) != tt.wantErr {
|
if err := ValidateAuthReqRedirectURI(tt.args.uri, tt.args.clientID, tt.args.storage); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("ValidateRedirectURI() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("ValidateRedirectURI() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package op
|
package op
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -180,22 +181,67 @@ func (p *DefaultOP) HandleDiscovery(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DefaultOP) HandleAuthorize(w http.ResponseWriter, r *http.Request) {
|
func (p *DefaultOP) HandleAuthorize(w http.ResponseWriter, r *http.Request) {
|
||||||
authRequest, err := ParseAuthRequest(w, r)
|
_, err := Authorize(w, r, p.storage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//TODO: return err
|
http.Error(w, err.Error(), 400)
|
||||||
}
|
}
|
||||||
err = ValidateAuthRequest(authRequest, p.storage)
|
// authRequest, err := ParseAuthRequest(w, r)
|
||||||
if err != nil {
|
|
||||||
//TODO: return err
|
|
||||||
}
|
|
||||||
// err = p.storage.CreateAuthRequest(authRequest)
|
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// //TODO: return err
|
// //TODO: return err
|
||||||
// }
|
// }
|
||||||
//TODO: redirect?
|
// err = ValidateAuthRequest(authRequest, p.storage)
|
||||||
|
// if err != nil {
|
||||||
|
// http.Error(w, err.Error(), 400)
|
||||||
|
// return
|
||||||
|
// //TODO: return err
|
||||||
|
// }
|
||||||
|
// // err = p.storage.CreateAuthRequest(authRequest)
|
||||||
|
// // if err != nil {
|
||||||
|
// // //TODO: return err
|
||||||
|
// // }
|
||||||
|
// var client oidc.Client
|
||||||
|
// RedirectToLogin(authRequest, client, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DefaultOP) HandleExchange(w http.ResponseWriter, r *http.Request) {
|
func (p *DefaultOP) HandleExchange(w http.ResponseWriter, r *http.Request) {
|
||||||
|
reqType := r.FormValue("grant_type")
|
||||||
|
if reqType == "" {
|
||||||
|
//return errors.New("grant_type missing") //TODO: impl
|
||||||
|
}
|
||||||
|
if reqType == string(oidc.GrantTypeCode) {
|
||||||
|
token, err := CodeExchange(w, r, p.storage)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(token)
|
||||||
|
w.Write(b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.handleTokenExchange(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (p *DefaultOP) handleCodeExchange(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// tokenRequest, err := ParseAccessTokenRequest(w, r)
|
||||||
|
// if err != nil {
|
||||||
|
// //TODO: return err
|
||||||
|
// }
|
||||||
|
// err = ValidateAccessTokenRequest(tokenRequest, p.storage)
|
||||||
|
// if err != nil {
|
||||||
|
// //TODO: return err
|
||||||
|
// }
|
||||||
|
// b, _ := json.Marshal(tokenRequest)
|
||||||
|
// w.Write(b)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (p *DefaultOP) handleTokenExchange(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tokenRequest, err := ParseTokenExchangeRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
//TODO: return err
|
||||||
|
}
|
||||||
|
err = ValidateTokenExchangeRequest(tokenRequest, p.storage)
|
||||||
|
if err != nil {
|
||||||
|
//TODO: return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DefaultOP) HandleUserinfo(w http.ResponseWriter, r *http.Request) {
|
func (p *DefaultOP) HandleUserinfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -21,4 +21,5 @@ require (
|
||||||
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/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,6 @@ package mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
oidc "github.com/caos/oidc/pkg/oidc"
|
oidc "github.com/caos/oidc/pkg/oidc"
|
||||||
op "github.com/caos/oidc/pkg/op"
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
)
|
)
|
||||||
|
@ -34,6 +33,51 @@ func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthRequestByCode mocks base method
|
||||||
|
func (m *MockStorage) AuthRequestByCode(arg0 oidc.Client, arg1, arg2 string) (*oidc.AuthRequest, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AuthRequestByCode", arg0, arg1, arg2)
|
||||||
|
ret0, _ := ret[0].(*oidc.AuthRequest)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthRequestByCode indicates an expected call of AuthRequestByCode
|
||||||
|
func (mr *MockStorageMockRecorder) AuthRequestByCode(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthRequestByCode", reflect.TypeOf((*MockStorage)(nil).AuthRequestByCode), arg0, arg1, arg2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeClientIDCodeVerifier mocks base method
|
||||||
|
func (m *MockStorage) AuthorizeClientIDCodeVerifier(arg0, arg1 string) (oidc.Client, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AuthorizeClientIDCodeVerifier", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(oidc.Client)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeClientIDCodeVerifier indicates an expected call of AuthorizeClientIDCodeVerifier
|
||||||
|
func (mr *MockStorageMockRecorder) AuthorizeClientIDCodeVerifier(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeClientIDCodeVerifier", reflect.TypeOf((*MockStorage)(nil).AuthorizeClientIDCodeVerifier), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeClientIDSecret mocks base method
|
||||||
|
func (m *MockStorage) AuthorizeClientIDSecret(arg0, arg1 string) (oidc.Client, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "AuthorizeClientIDSecret", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(oidc.Client)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeClientIDSecret indicates an expected call of AuthorizeClientIDSecret
|
||||||
|
func (mr *MockStorageMockRecorder) AuthorizeClientIDSecret(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthorizeClientIDSecret", reflect.TypeOf((*MockStorage)(nil).AuthorizeClientIDSecret), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateAuthRequest mocks base method
|
// CreateAuthRequest mocks base method
|
||||||
func (m *MockStorage) CreateAuthRequest(arg0 *oidc.AuthRequest) error {
|
func (m *MockStorage) CreateAuthRequest(arg0 *oidc.AuthRequest) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -48,11 +92,25 @@ func (mr *MockStorageMockRecorder) CreateAuthRequest(arg0 interface{}) *gomock.C
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthRequest", reflect.TypeOf((*MockStorage)(nil).CreateAuthRequest), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAuthRequest", reflect.TypeOf((*MockStorage)(nil).CreateAuthRequest), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteAuthRequestAndCode mocks base method
|
||||||
|
func (m *MockStorage) DeleteAuthRequestAndCode(arg0, arg1 string) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "DeleteAuthRequestAndCode", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAuthRequestAndCode indicates an expected call of DeleteAuthRequestAndCode
|
||||||
|
func (mr *MockStorageMockRecorder) DeleteAuthRequestAndCode(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAuthRequestAndCode", reflect.TypeOf((*MockStorage)(nil).DeleteAuthRequestAndCode), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// GetClientByClientID mocks base method
|
// GetClientByClientID mocks base method
|
||||||
func (m *MockStorage) GetClientByClientID(arg0 string) (op.Client, error) {
|
func (m *MockStorage) GetClientByClientID(arg0 string) (oidc.Client, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "GetClientByClientID", arg0)
|
ret := m.ctrl.Call(m, "GetClientByClientID", arg0)
|
||||||
ret0, _ := ret[0].(op.Client)
|
ret0, _ := ret[0].(oidc.Client)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
"github.com/caos/oidc/pkg/op"
|
"github.com/caos/oidc/pkg/op"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,6 +19,14 @@ func NewMockStorageExpectValidClientID(t *testing.T) op.Storage {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewMockStorageAny(t *testing.T) op.Storage {
|
||||||
|
m := NewStorage(t)
|
||||||
|
mockS := m.(*MockStorage)
|
||||||
|
mockS.EXPECT().GetClientByClientID(gomock.Any()).AnyTimes().Return(&ConfClient{}, nil)
|
||||||
|
mockS.EXPECT().AuthorizeClientIDSecret(gomock.Any(), gomock.Any()).AnyTimes().Return(&ConfClient{}, nil)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
func ExpectValidClientID(s op.Storage) {
|
func ExpectValidClientID(s op.Storage) {
|
||||||
mockS := s.(*MockStorage)
|
mockS := s.(*MockStorage)
|
||||||
mockS.EXPECT().GetClientByClientID(gomock.Any()).Return(&ConfClient{}, nil)
|
mockS.EXPECT().GetClientByClientID(gomock.Any()).Return(&ConfClient{}, nil)
|
||||||
|
@ -25,8 +34,8 @@ func ExpectValidClientID(s op.Storage) {
|
||||||
|
|
||||||
type ConfClient struct{}
|
type ConfClient struct{}
|
||||||
|
|
||||||
func (c *ConfClient) Type() op.ClientType {
|
func (c *ConfClient) Type() oidc.ClientType {
|
||||||
return op.ClientTypeConfidential
|
return oidc.ClientTypeConfidential
|
||||||
}
|
}
|
||||||
func (c *ConfClient) RedirectURIs() []string {
|
func (c *ConfClient) RedirectURIs() []string {
|
||||||
return []string{
|
return []string{
|
||||||
|
@ -35,3 +44,7 @@ func (c *ConfClient) RedirectURIs() []string {
|
||||||
"custom://callback",
|
"custom://callback",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ConfClient) LoginURL(id string) string {
|
||||||
|
return "login?id=" + id
|
||||||
|
}
|
|
@ -4,21 +4,9 @@ import "github.com/caos/oidc/pkg/oidc"
|
||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
CreateAuthRequest(*oidc.AuthRequest) error
|
CreateAuthRequest(*oidc.AuthRequest) error
|
||||||
GetClientByClientID(string) (Client, error)
|
GetClientByClientID(string) (oidc.Client, error)
|
||||||
|
AuthRequestByCode(oidc.Client, string, string) (*oidc.AuthRequest, error)
|
||||||
|
AuthorizeClientIDSecret(string, string) (oidc.Client, error)
|
||||||
|
AuthorizeClientIDCodeVerifier(string, string) (oidc.Client, error)
|
||||||
|
DeleteAuthRequestAndCode(string, string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client interface {
|
|
||||||
RedirectURIs() []string
|
|
||||||
Type() ClientType
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientType int
|
|
||||||
|
|
||||||
func (c ClientType) IsConvidential() bool {
|
|
||||||
return c == ClientTypeConfidential
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
ClientTypeConfidential ClientType = iota
|
|
||||||
ClientTypePublic
|
|
||||||
)
|
|
||||||
|
|
100
pkg/op/tokenrequest.go
Normal file
100
pkg/op/tokenrequest.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package op
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/schema"
|
||||||
|
|
||||||
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// func ParseTokenRequest(w http.ResponseWriter, r *http.Request) (oidc.TokenRequest, error) {
|
||||||
|
// reqType := r.FormValue("grant_type")
|
||||||
|
// if reqType == "" {
|
||||||
|
// return nil, errors.New("grant_type missing") //TODO: impl
|
||||||
|
// }
|
||||||
|
// if reqType == string(oidc.GrantTypeCode) {
|
||||||
|
// return ParseAccessTokenRequest(w, r)
|
||||||
|
// }
|
||||||
|
// return ParseTokenExchangeRequest(w, r)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func CodeExchange(w http.ResponseWriter, r *http.Request, storage Storage) (*oidc.AccessTokenResponse, error) {
|
||||||
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Unimplemented") //TODO: impl
|
||||||
|
}
|
||||||
|
tokenReq := new(oidc.AccessTokenRequest)
|
||||||
|
|
||||||
|
//TODO:
|
||||||
|
d := schema.NewDecoder()
|
||||||
|
d.IgnoreUnknownKeys(true)
|
||||||
|
|
||||||
|
err = d.Decode(tokenReq, r.Form)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if tokenReq.Code == "" {
|
||||||
|
return nil, errors.New("code missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := AuthorizeClient(r, tokenReq, storage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authReq, err := storage.AuthRequestByCode(client, tokenReq.Code, tokenReq.RedirectURI)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
err = storage.DeleteAuthRequestAndCode(authReq.ID, tokenReq.Code)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
accessToken, err := CreateAccessToken()
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
idToken, err := CreateIDToken()
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &oidc.AccessTokenResponse{
|
||||||
|
AccessToken: accessToken,
|
||||||
|
IDToken: idToken,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateAccessToken() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
func CreateIDToken() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AuthorizeClient(r *http.Request, tokenReq *oidc.AccessTokenRequest, storage Storage) (oidc.Client, error) {
|
||||||
|
if tokenReq.ClientID == "" {
|
||||||
|
clientID, clientSecret, ok := r.BasicAuth()
|
||||||
|
if ok {
|
||||||
|
return storage.AuthorizeClientIDSecret(clientID, clientSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if tokenReq.ClientSecret != "" {
|
||||||
|
return storage.AuthorizeClientIDSecret(tokenReq.ClientID, tokenReq.ClientSecret)
|
||||||
|
}
|
||||||
|
if tokenReq.CodeVerifier != "" {
|
||||||
|
return storage.AuthorizeClientIDCodeVerifier(tokenReq.ClientID, tokenReq.CodeVerifier)
|
||||||
|
}
|
||||||
|
return nil, errors.New("Unimplemented") //TODO: impl
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseTokenExchangeRequest(w http.ResponseWriter, r *http.Request) (oidc.TokenRequest, error) {
|
||||||
|
return nil, errors.New("Unimplemented") //TODO: impl
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateTokenExchangeRequest(tokenReq oidc.TokenRequest, storage Storage) error {
|
||||||
|
|
||||||
|
return errors.New("Unimplemented") //TODO: impl
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue