X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/4312333bb8bd27e0b910b430edee91329124b02a..765604b096c464b242e60860ace75bd6645fd4e7:/sdk/go/arvadostest/oidc_provider.go diff --git a/sdk/go/arvadostest/oidc_provider.go b/sdk/go/arvadostest/oidc_provider.go index 0632010ba4..529c1dca12 100644 --- a/sdk/go/arvadostest/oidc_provider.go +++ b/sdk/go/arvadostest/oidc_provider.go @@ -9,6 +9,7 @@ import ( "crypto/rsa" "encoding/base64" "encoding/json" + "fmt" "net/http" "net/http/httptest" "net/url" @@ -17,6 +18,7 @@ import ( "gopkg.in/check.v1" "gopkg.in/square/go-jose.v2" + "gopkg.in/square/go-jose.v2/jwt" ) type OIDCProvider struct { @@ -25,12 +27,22 @@ type OIDCProvider struct { ValidClientID string ValidClientSecret string // desired response from token endpoint - AuthEmail string - AuthEmailVerified bool - AuthName string + AuthEmail string + AuthEmailVerified bool + AuthName string + AuthGivenName string + AuthFamilyName string + AccessTokenPayload map[string]interface{} PeopleAPIResponse map[string]interface{} + // send incoming /userinfo requests to HoldUserInfo (if not + // nil), then receive from ReleaseUserInfo (if not nil), + // before responding (these are used to set up races) + HoldUserInfo chan *http.Request + ReleaseUserInfo chan struct{} + UserInfoErrorStatus int // if non-zero, return this http status (probably 5xx) + key *rsa.PrivateKey Issuer *httptest.Server PeopleAPI *httptest.Server @@ -44,9 +56,15 @@ func NewOIDCProvider(c *check.C) *OIDCProvider { c.Assert(err, check.IsNil) p.Issuer = httptest.NewServer(http.HandlerFunc(p.serveOIDC)) p.PeopleAPI = httptest.NewServer(http.HandlerFunc(p.servePeopleAPI)) + p.AccessTokenPayload = map[string]interface{}{"sub": "example"} return p } +func (p *OIDCProvider) ValidAccessToken() string { + buf, _ := json.Marshal(p.AccessTokenPayload) + return p.fakeToken(buf) +} + func (p *OIDCProvider) serveOIDC(w http.ResponseWriter, req *http.Request) { req.ParseForm() p.c.Logf("serveOIDC: got req: %s %s %s", req.Method, req.URL, req.Form) @@ -88,6 +106,8 @@ func (p *OIDCProvider) serveOIDC(w http.ResponseWriter, req *http.Request) { "email": p.AuthEmail, "email_verified": p.AuthEmailVerified, "name": p.AuthName, + "given_name": p.AuthGivenName, + "family_name": p.AuthFamilyName, "alt_verified": true, // for custom claim tests "alt_email": "alt_email@example.com", // for custom claim tests "alt_username": "desired-username", // for custom claim tests @@ -99,7 +119,7 @@ func (p *OIDCProvider) serveOIDC(w http.ResponseWriter, req *http.Request) { ExpiresIn int32 `json:"expires_in"` IDToken string `json:"id_token"` }{ - AccessToken: p.fakeToken([]byte("fake access token")), + AccessToken: p.ValidAccessToken(), TokenType: "Bearer", RefreshToken: "test-refresh-token", ExpiresIn: 30, @@ -114,7 +134,32 @@ func (p *OIDCProvider) serveOIDC(w http.ResponseWriter, req *http.Request) { case "/auth": w.WriteHeader(http.StatusInternalServerError) case "/userinfo": - w.WriteHeader(http.StatusInternalServerError) + if p.HoldUserInfo != nil { + p.HoldUserInfo <- req + } + if p.ReleaseUserInfo != nil { + <-p.ReleaseUserInfo + } + if p.UserInfoErrorStatus > 0 { + w.WriteHeader(p.UserInfoErrorStatus) + fmt.Fprintf(w, "%T error body", p) + return + } + authhdr := req.Header.Get("Authorization") + if _, err := jwt.ParseSigned(strings.TrimPrefix(authhdr, "Bearer ")); err != nil { + p.c.Logf("OIDCProvider: bad auth %q", authhdr) + w.WriteHeader(http.StatusUnauthorized) + return + } + json.NewEncoder(w).Encode(map[string]interface{}{ + "sub": "fake-user-id", + "name": p.AuthName, + "given_name": p.AuthGivenName, + "family_name": p.AuthFamilyName, + "alt_username": "desired-username", + "email": p.AuthEmail, + "email_verified": p.AuthEmailVerified, + }) default: w.WriteHeader(http.StatusNotFound) }