func TestAuthValidateCodeResponseAuthenticateOk(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) var loginCalled = false ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { loginCalled = true w.WriteHeader(http.StatusOK) })) defer ls.Close() //TODO - use a second callback where we serve up a script to extract the page details sent //on deny and post those details to another test server. var callbackInvoked = false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { callbackInvoked = true code := r.FormValue("code") token, err := jwt.Parse(code, rolltoken.GenerateKeyExtractionFunction(core.SecretsRepo)) assert.Nil(t, err) scope, ok := token.Claims["scope"].(string) assert.True(t, ok) assert.Equal(t, "xtAuthCode", scope) })) defer ts.Close() lsURL, _ := url.Parse(ls.URL) returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: ts.URL, LoginProvider: "xtrac://" + lsURL.Host, } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) _, err = http.PostForm(addr+"/oauth2/validate", url.Values{"username": {"x"}, "password": {"y"}, "authorize": {"allow"}, "response_type": {"code"}, "client_id": {"1111-2222-3333333-4444444"}}) assert.Nil(t, err) assert.True(t, callbackInvoked) assert.True(t, loginCalled) }
func TestPWGrantLoginOk(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() var loginCalled = false ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { loginCalled = true w.WriteHeader(http.StatusOK) })) defer ls.Close() lsURL, _ := url.Parse(ls.URL) returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://" + lsURL.Host, } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) resp, err := http.PostForm(addr+OAuth2TokenBaseURI, url.Values{"grant_type": {"password"}, "client_id": {"1111-2222-3333333-4444444"}, "client_secret": {"not for browser clients"}, "username": {"abc"}, "password": {"xxxxxxxx"}}) assert.True(t, loginCalled) assert.Nil(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) body := responseAsString(t, resp) var jsonResponse accessTokenResponse err = json.Unmarshal([]byte(body), &jsonResponse) assert.Nil(t, err) assert.True(t, jsonResponse.AccessToken != "") assert.True(t, jsonResponse.TokenType == "Bearer") token, err := jwt.Parse(jsonResponse.AccessToken, rolltoken.GenerateKeyExtractionFunction(core.SecretsRepo)) assert.Nil(t, err) fmt.Println(token.Claims) assert.Equal(t, "1111-2222-3333333-4444444", token.Claims["aud"].(string)) assert.Equal(t, "abc", token.Claims["sub"].(string)) assert.Equal(t, "", token.Claims["scope"].(string)) }
func TestAuthValidateCodeResponseAuthenticateAdminScopeError(t *testing.T) { var loginCalled = false ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { loginCalled = true w.WriteHeader(http.StatusOK) })) defer ls.Close() //TODO - use a second callback where we serve up a script to extract the page details sent //on deny and post those details to another test server. var callbackInvoked = false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { callbackInvoked = true assert.True(t, strings.Contains(r.RequestURI, "error=server_error&error_description=")) })) defer ts.Close() core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() lsURL, _ := url.Parse(ls.URL) returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: ts.URL + "/foo", LoginProvider: "xtrac://" + lsURL.Host, } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) adminRepoMock := coreConfig.AdminRepo.(*mocks.AdminRepo) adminRepoMock.On("IsAdmin", "x").Return(false, errors.New("BOOM!")) privateKey, _, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) _, err = http.PostForm(addr+"/oauth2/validate", url.Values{"username": {"x"}, "password": {"y"}, "authorize": {"allow"}, "response_type": {"code"}, "scope": {"admin"}, "client_id": {"1111-2222-3333333-4444444"}}) assert.Nil(t, err) assert.True(t, callbackInvoked) }
func TestTokenSignedWithWrongKey(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://localhost:9000", } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) otherKey, _, err := secrets.GenerateKeyPair() assert.Nil(t, err) code, err := rolltoken.GenerateCode("a-subject", "", returnVal.ClientID, otherKey) assert.Nil(t, err) resp, err := http.PostForm(addr+OAuth2TokenBaseURI, url.Values{"grant_type": {"authorization_code"}, "client_id": {"1111-2222-3333333-4444444"}, "client_secret": {"not for browser clients"}, "redirect_uri": {"http://localhost:3000/ab"}, "code": {code}}) assert.Nil(t, err) body := responseAsString(t, resp) assert.True(t, strings.Contains(body, "verification error")) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }
func TestInvalidSignature(t *testing.T) { app := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://localhost:9000", } appRepoMock := new(mocks.ApplicationRepo) appRepoMock.On("RetrieveApplication", "1111-2222-3333333-4444444").Return(&app, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) private2, _, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := new(mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) adminRepo := new(mocks.AdminRepo) token, err := rolltoken.GenerateToken("b-subject", "", app.ClientID, app.ApplicationName, private2) assert.Nil(t, err) testServer := httptest.NewServer(Wrap(secretsMock, adminRepo, []string{}, echoHandler())) defer testServer.Close() client := http.Client{} req, err := http.NewRequest("POST", testServer.URL, nil) assert.Nil(t, err) req.Header.Add("Authorization", "Bearer "+token) resp, err := client.Do(req) assert.Nil(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }
func TestTokenValidCodeWithAdminScope(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://localhost:9000", } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) code, err := rolltoken.GenerateCode("b-subject", "admin", returnVal.ClientID, privateKey) assert.Nil(t, err) resp, err := http.PostForm(addr+OAuth2TokenBaseURI, url.Values{"grant_type": {"authorization_code"}, "client_id": {"1111-2222-3333333-4444444"}, "client_secret": {"not for browser clients"}, "redirect_uri": {"http://localhost:3000/ab"}, "code": {code}}) assert.Nil(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) body := responseAsString(t, resp) var jsonResponse accessTokenResponse err = json.Unmarshal([]byte(body), &jsonResponse) assert.Nil(t, err) assert.True(t, jsonResponse.AccessToken != "") assert.True(t, jsonResponse.TokenType == "Bearer") token, err := jwt.Parse(jsonResponse.AccessToken, rolltoken.GenerateKeyExtractionFunction(core.SecretsRepo)) assert.Nil(t, err) scope, ok := token.Claims["scope"].(string) assert.True(t, ok) assert.Equal(t, "admin", scope) }
func TestPWGrantLoginOkInvalidScope(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() var loginCalled = false ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { loginCalled = true w.WriteHeader(http.StatusOK) })) defer ls.Close() lsURL, _ := url.Parse(ls.URL) returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://" + lsURL.Host, } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) adminRepoMock := coreConfig.AdminRepo.(*mocks.AdminRepo) adminRepoMock.On("IsAdmin", "abc").Return(true, nil) resp, err := http.PostForm(addr+OAuth2TokenBaseURI, url.Values{"grant_type": {"password"}, "client_id": {"1111-2222-3333333-4444444"}, "client_secret": {"not for browser clients"}, "username": {"abc"}, "scope": {"adminxxx"}, "password": {"xxxxxxxx"}}) assert.True(t, loginCalled) assert.Nil(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) }
func TestJWTFlowValidAssertionOkYeah(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://localhost:9000", JWTFlowPublicKey: publicKey, JWTFlowIssuer: "1111-2222-3333333-4444444", JWTFlowAudience: "captive", } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplicationByJWTFlowAudience", "captive").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) resp, err := http.PostForm(addr+OAuth2TokenBaseURI, url.Values{"grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, "assertion": {jwtAssertion}}) assert.Nil(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) bodyStr := responseAsString(t, resp) println(bodyStr) var jsonResponse accessTokenResponse err = json.Unmarshal([]byte(bodyStr), &jsonResponse) assert.Nil(t, err) assert.True(t, jsonResponse.AccessToken != "") assert.True(t, jsonResponse.TokenType == "Bearer") token, err := jwt.Parse(jsonResponse.AccessToken, rolltoken.GenerateKeyExtractionFunction(core.SecretsRepo)) assert.Nil(t, err) assert.Equal(t, "1111-2222-3333333-4444444", token.Claims["aud"].(string)) assert.Equal(t, "foo", token.Claims["sub"].(string)) assert.Equal(t, "", token.Claims["scope"].(string)) }
func TestValidAccessToken(t *testing.T) { core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: "http://localhost:3000/ab", LoginProvider: "xtrac://localhost:9000", } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("RetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, publicKey, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(publicKey, nil) token, err := rolltoken.GenerateToken("a-subject", "", returnVal.ClientID, returnVal.ApplicationName, privateKey) assert.Nil(t, err) resp, err := http.Get(addr + TokenInfoURI + "?access_token=" + token) assert.Nil(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) body := responseAsString(t, resp) var ti tokenInfo err = json.Unmarshal([]byte(body), &ti) assert.Nil(t, err) assert.Equal(t, "1111-2222-3333333-4444444", ti.Audience) }
func TestImplGrantAuthValidateAuthenticateOkAdminScope(t *testing.T) { var loginCalled = false ls := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { loginCalled = true w.WriteHeader(http.StatusOK) })) defer ls.Close() //TODO - use a second callback where we serve up a script to extract the page details sent //on deny and post those details to another test server. var callbackInvoked = false ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { callbackInvoked = true println(r.URL.RawQuery) })) defer ts.Close() core, coreConfig := NewTestCore() ln, addr := TestServer(t, core) defer ln.Close() lsURL, _ := url.Parse(ls.URL) returnVal := roll.Application{ DeveloperEmail: "*****@*****.**", ClientID: "1111-2222-3333333-4444444", ApplicationName: "fight club", ClientSecret: "not for browser clients", RedirectURI: ts.URL + "/foo", LoginProvider: "xtrac://" + lsURL.Host, } appRepoMock := coreConfig.ApplicationRepo.(*mocks.ApplicationRepo) appRepoMock.On("SystemRetrieveApplication", "1111-2222-3333333-4444444").Return(&returnVal, nil) privateKey, pk, err := secrets.GenerateKeyPair() assert.Nil(t, err) secretsMock := coreConfig.SecretsRepo.(*mocks.SecretsRepo) secretsMock.On("RetrievePrivateKeyForApp", "1111-2222-3333333-4444444").Return(privateKey, nil) secretsMock.On("RetrievePublicKeyForApp", "1111-2222-3333333-4444444").Return(pk, nil) adminRepoMock := coreConfig.AdminRepo.(*mocks.AdminRepo) adminRepoMock.On("IsAdmin", "x").Return(true, nil) client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { fmt.Println(req.URL.Fragment) m, _ := url.ParseQuery(req.URL.Fragment) accessToken := m.Get("access_token") token, err := jwt.Parse(accessToken, rolltoken.GenerateKeyExtractionFunction(core.SecretsRepo)) assert.Nil(t, err) scope, ok := token.Claims["scope"].(string) assert.True(t, ok) assert.Equal(t, "admin", scope) assert.Equal(t, "x", token.Claims["sub"].(string)) assert.Equal(t, "1111-2222-3333333-4444444", token.Claims["aud"].(string)) assert.Equal(t, "Bearer", m.Get("token_type")) return nil }, } _, err = client.PostForm(addr+"/oauth2/validate", url.Values{"username": {"x"}, "password": {"y"}, "authorize": {"allow"}, "response_type": {"token"}, "scope": {"admin"}, "client_id": {"1111-2222-3333333-4444444"}}) assert.Nil(t, err) assert.True(t, callbackInvoked) assert.True(t, loginCalled) }
func handleApplicationPost(core *roll.Core, w http.ResponseWriter, r *http.Request) { var app roll.Application if err := parseRequest(r, &app); err != nil { respondError(w, http.StatusBadRequest, err) return } //Assign a client ID id, err := core.GenerateID() if err != nil { respondError(w, http.StatusInternalServerError, err) return } app.ClientID = id //Validate the content if err := app.Validate(); err != nil { respondError(w, http.StatusBadRequest, err) return } //Extract the subject from the request header based on security mode subject, _, err := subjectAndAdminScopeFromRequestCtx(r) if err != nil { log.Print("Error extracting subject:", err.Error()) respondError(w, http.StatusInternalServerError, nil) return } app.DeveloperID = subject //Store the application definition log.Info("storing app def: ", app) err = core.CreateApplication(&app) if err != nil { log.Info("Error storing app def: ", err.Error()) switch err.(type) { case *repos.DuplicateAppdefError: respondError(w, http.StatusConflict, err) default: respondError(w, http.StatusInternalServerError, err) } return } //Generate a private/public key pair log.Info("Generate key pair") private, public, err := secrets.GenerateKeyPair() if err != nil { respondError(w, http.StatusBadRequest, err) return } //Store keys in secrets vault log.Info("store key pair in vault") err = core.StoreKeysForApp(id, private, public) if err != nil { respondError(w, http.StatusInternalServerError, err) return } //Return the client id log.Info("return client id: ", id) clientID := ApplicationCreatedResponse{ClientID: id} respondOk(w, clientID) }