fix: improve example & fix userinfo marshal (#132)

* fix: example client should track state, call cli.CodeFlow need context

* fix: oidc userinfo can UnmarshalJSON with address

* rp Discover use client.Discover

* add instruction for example to README.md
This commit is contained in:
陈杨文 2021-10-08 14:20:45 +08:00 committed by GitHub
parent a63fbee93d
commit ff2c164057
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 48 additions and 7 deletions

View file

@ -21,6 +21,18 @@ Whenever possible we tried to reuse / extend existing packages like `OAuth2 for
Check the `/example` folder where example code for different scenarios is located.
```bash
# start oidc op server
# oidc discovery http://localhost:9998/.well-known/openid-configuration
CAOS_OIDC_DEV=1 go run github.com/caos/oidc/example/server/default
# start oidc web client
CLIENT_ID=web CLIENT_SECRET=web ISSUER=http://localhost:9998/ SCOPES=openid PORT=5556 go run github.com/caos/oidc/example/client/app
```
- browser http://localhost:5556/login will redirect to op server
- input id to login
- redirect to client app display user info
## Features
| | Code Flow | Implicit Flow | Hybrid Flow | Discovery | PKCE | Token Exchange | mTLS | JWT Profile | Refresh Token |

View file

@ -43,7 +43,7 @@ func main() {
state := func() string {
return uuid.New().String()
}
token := cli.CodeFlow(relyingParty, callbackPath, port, state)
token := cli.CodeFlow(ctx, relyingParty, callbackPath, port, state)
client := github.NewClient(relyingParty.OAuthConfig().Client(ctx, token.Token))

View file

@ -36,6 +36,7 @@ type AuthRequest struct {
Nonce string
ClientID string
CodeChallenge *oidc.CodeChallenge
State string
}
func (a *AuthRequest) GetACR() string {
@ -98,7 +99,7 @@ func (a *AuthRequest) GetScopes() []string {
func (a *AuthRequest) SetCurrentScopes(scopes []string) {}
func (a *AuthRequest) GetState() string {
return ""
return a.State
}
func (a *AuthRequest) GetSubject() string {
@ -120,7 +121,7 @@ func (s *AuthStorage) Health(ctx context.Context) error {
}
func (s *AuthStorage) CreateAuthRequest(_ context.Context, authReq *oidc.AuthRequest, _ string) (op.AuthRequest, error) {
a = &AuthRequest{ID: "id", ClientID: authReq.ClientID, ResponseType: authReq.ResponseType, Nonce: authReq.Nonce, RedirectURI: authReq.RedirectURI}
a = &AuthRequest{ID: "id", ClientID: authReq.ClientID, ResponseType: authReq.ResponseType, Nonce: authReq.Nonce, RedirectURI: authReq.RedirectURI, State: authReq.State}
if authReq.CodeChallenge != "" {
a.CodeChallenge = &oidc.CodeChallenge{
Challenge: authReq.CodeChallenge,
@ -212,7 +213,7 @@ func (s *AuthStorage) GetClientByClientID(_ context.Context, id string) (op.Clie
accessTokenType = op.AccessTokenTypeJWT
responseTypes = []oidc.ResponseType{oidc.ResponseTypeIDToken, oidc.ResponseTypeIDTokenOnly}
}
return &ConfClient{ID: id, applicationType: appType, authMethod: authMethod, accessTokenType: accessTokenType, responseTypes: responseTypes, devMode: false}, nil
return &ConfClient{ID: id, applicationType: appType, authMethod: authMethod, accessTokenType: accessTokenType, responseTypes: responseTypes, devMode: false, grantTypes: []oidc.GrantType{oidc.GrantTypeCode}}, nil
}
func (s *AuthStorage) AuthorizeClientIDSecret(_ context.Context, id string, _ string) error {

View file

@ -170,17 +170,18 @@ func NewRelyingPartyOIDC(issuer, clientID, clientSecret, redirectURI string, sco
return nil, err
}
}
endpoints, err := Discover(rp.issuer, rp.httpClient)
discoveryConfiguration, err := client.Discover(rp.issuer, rp.httpClient)
if err != nil {
return nil, err
}
endpoints := GetEndpoints(discoveryConfiguration)
rp.oauthConfig.Endpoint = endpoints.Endpoint
rp.endpoints = endpoints
return rp, nil
}
//DefaultRPOpts is the type for providing dynamic options to the DefaultRP
//Option is the type for providing dynamic options to the DefaultRP
type Option func(*relyingParty) error
//WithCookieHandler set a `CookieHandler` for securing the various redirects

View file

@ -360,6 +360,7 @@ func (i *userinfo) MarshalJSON() ([]byte, error) {
func (i *userinfo) UnmarshalJSON(data []byte) error {
type Alias userinfo
a := &struct {
Address *userInfoAddress `json:"address,omitempty"`
*Alias
UpdatedAt int64 `json:"update_at,omitempty"`
}{
@ -368,7 +369,7 @@ func (i *userinfo) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &a); err != nil {
return err
}
i.Address = a.Address
i.UpdatedAt = Time(time.Unix(a.UpdatedAt, 0).UTC())
if err := json.Unmarshal(data, &i.claims); err != nil {

26
pkg/oidc/userinfo_test.go Normal file
View file

@ -0,0 +1,26 @@
package oidc
import (
"encoding/json"
"github.com/stretchr/testify/assert"
"testing"
)
func TestUserInfoMarshal(t *testing.T) {
userinfo := NewUserInfo()
userinfo.SetSubject("test")
userinfo.SetAddress(NewUserInfoAddress("Test 789\nPostfach 2", "", "", "", "", ""))
userinfo.SetEmail("test", true)
userinfo.SetPhone("0791234567", true)
userinfo.SetName("Test")
userinfo.AppendClaims("private_claim", "test")
marshal, err := json.Marshal(userinfo)
out := NewUserInfo()
assert.NoError(t, err)
assert.NoError(t, json.Unmarshal(marshal, out))
assert.Equal(t, userinfo.GetAddress(), out.GetAddress())
expected, err := json.Marshal(out)
assert.NoError(t, err)
assert.Equal(t, expected, marshal)
}