func TestCallbackHandler_ParseCallbackError(t *testing.T) { config := &oauth2.Config{} success := testutils.AssertSuccessNotCalled(t) failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { assert.Equal(t, "oauth2: Request missing code or state", err.Error()) } fmt.Fprintf(w, "failure handler called") } // CallbackHandler called without code or state, assert that: // - failure handler is called // - error about missing code or state is added to the ctx callbackHandler := CallbackHandler(config, success, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/?code=any_code", nil) ctxh.NewHandler(callbackHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) w = httptest.NewRecorder() req, _ = http.NewRequest("GET", "/?state=any_state", nil) ctxh.NewHandler(callbackHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }
// New returns a new ServeMux with app routes. func New(config *Config) *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("/", welcomeHandler) mux.Handle("/profile", requireLogin(http.HandlerFunc(profileHandler))) mux.HandleFunc("/logout", logoutHandler) // 1. Register Twitter login and callback handlers oauth1Config := &oauth1.Config{ ConsumerKey: config.TwitterConsumerKey, ConsumerSecret: config.TwitterConsumerSecret, CallbackURL: "http://localhost:8080/twitter/callback", Endpoint: twitterOAuth1.AuthorizeEndpoint, } mux.Handle("/twitter/login", ctxh.NewHandler(twitter.LoginHandler(oauth1Config, nil))) mux.Handle("/twitter/callback", ctxh.NewHandler(twitter.CallbackHandler(oauth1Config, issueSession(), nil))) return mux }
func TestWebHandler_InvalidFields(t *testing.T) { config := &Config{ ConsumerKey: testConsumerKey, } handler := LoginHandler(config, testutils.AssertSuccessNotCalled(t), nil) ts := httptest.NewServer(ctxh.NewHandler(handler)) // assert errors occur for different missing/incorrect POST fields resp, err := http.PostForm(ts.URL, url.Values{"wrongKeyName": {testAccountEndpoint}, accountRequestHeaderField: {testAccountRequestHeader}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrMissingAccountEndpoint.Error()+"\n") resp, err = http.PostForm(ts.URL, url.Values{accountEndpointField: {"https://evil.com"}, accountRequestHeaderField: {testAccountRequestHeader}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrInvalidDigitsEndpoint.Error()+"\n") resp, err = http.PostForm(ts.URL, url.Values{accountEndpointField: {testAccountEndpoint}, accountRequestHeaderField: {`OAuth oauth_consumer_key="notmyconsumerkey",`}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrInvalidConsumerKey.Error()+"\n") // valid, but incorrect Digits account endpoint resp, err = http.PostForm(ts.URL, url.Values{accountEndpointField: {"https://api.digits.com/1.1/wrong.json"}, accountRequestHeaderField: {testAccountRequestHeader}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrUnableToGetDigitsAccount.Error()+"\n") }
func TestWebHandler(t *testing.T) { proxyClient, _, server := newDigitsTestServer(testAccountJSON) defer server.Close() config := &Config{ ConsumerKey: testConsumerKey, Client: proxyClient, } success := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { account, err := AccountFromContext(ctx) assert.Nil(t, err) assert.Equal(t, testDigitsToken, account.AccessToken.Token) assert.Equal(t, testDigitsSecret, account.AccessToken.Secret) assert.Equal(t, "0123456789", account.PhoneNumber) endpoint, header, err := EchoFromContext(ctx) assert.Nil(t, err) assert.Equal(t, testAccountEndpoint, endpoint) assert.Equal(t, testAccountRequestHeader, header) } handler := LoginHandler(config, ctxh.ContextHandlerFunc(success), testutils.AssertFailureNotCalled(t)) ts := httptest.NewServer(ctxh.NewHandler(handler)) // POST OAuth Echo to server under test resp, err := http.PostForm(ts.URL, url.Values{accountEndpointField: {testAccountEndpoint}, accountRequestHeaderField: {testAccountRequestHeader}}) assert.Nil(t, err) if assert.NotNil(t, resp) { assert.Equal(t, http.StatusOK, resp.StatusCode) } }
func TestLoginHandler_RequestTokenError(t *testing.T) { server := testutils.NewErrorServer(t, "OAuth1 Service Down", http.StatusInternalServerError) defer server.Close() config := &oauth1.Config{ Endpoint: oauth1.Endpoint{ RequestTokenURL: server.URL, }, } success := testutils.AssertSuccessNotCalled(t) failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { // first validation in OAuth1 impl failed assert.Equal(t, "oauth1: oauth_callback_confirmed was not true", err.Error()) } fmt.Fprintf(w, "failure handler called") } // LoginHandler cannot get the OAuth1 request token, assert that: // - failure handler is called // - error is added to the ctx of the failure handler loginHandler := LoginHandler(config, success, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) ctxh.NewHandler(loginHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }
func TestLoginHandler(t *testing.T) { expectedToken := "request_token" expectedSecret := "request_secret" data := url.Values{} data.Add("oauth_token", expectedToken) data.Add("oauth_token_secret", expectedSecret) data.Add("oauth_callback_confirmed", "true") server := NewRequestTokenServer(t, data) defer server.Close() config := &oauth1.Config{ Endpoint: oauth1.Endpoint{ RequestTokenURL: server.URL, }, } success := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { requestToken, requestSecret, err := RequestTokenFromContext(ctx) assert.Equal(t, expectedToken, requestToken) assert.Equal(t, expectedSecret, requestSecret) assert.Nil(t, err) fmt.Fprintf(w, "success handler called") } failure := testutils.AssertFailureNotCalled(t) // LoginHandler gets OAuth1 request token, assert that: // - success handler is called // - request token added to the ctx of the success handler // - request secret added to the ctx of the success handler // - failure handler is not called loginHandler := LoginHandler(config, ctxh.ContextHandlerFunc(success), failure) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) ctxh.NewHandler(loginHandler).ServeHTTP(w, req) assert.Equal(t, "success handler called", w.Body.String()) }
// New returns a new ServeMux with app routes. func New(config *Config) *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("/", welcomeHandler) mux.Handle("/profile", requireLogin(http.HandlerFunc(profileHandler))) mux.HandleFunc("/logout", logoutHandler) // 1. Register Login and Callback handlers oauth2Config := &oauth2.Config{ ClientID: config.FacebookClientID, ClientSecret: config.FacebookClientSecret, RedirectURL: "http://localhost:8080/facebook/callback", Endpoint: facebookOAuth2.Endpoint, } // state param cookies require HTTPS by default; disable for localhost development stateConfig := gologin.DebugOnlyCookieConfig mux.Handle("/facebook/login", ctxh.NewHandler(facebook.StateHandler(stateConfig, facebook.LoginHandler(oauth2Config, nil)))) mux.Handle("/facebook/callback", ctxh.NewHandler(facebook.StateHandler(stateConfig, facebook.CallbackHandler(oauth2Config, issueSession(), nil)))) return mux }
func TestTokenHandler_NonPost(t *testing.T) { config := &oauth1.Config{} ts := httptest.NewServer(ctxh.NewHandler(TokenHandler(config, assertSuccessNotCalled(t), nil))) resp, err := http.Get(ts.URL) assert.Nil(t, err) // assert that default (nil) failure handler returns a 405 Method Not Allowed if assert.NotNil(t, resp) { // TODO: change to 405 assert.Equal(t, http.StatusBadRequest, resp.StatusCode) } }
func TestTokenHandler_NonPostPassesError(t *testing.T) { config := &oauth1.Config{} failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { // assert that Method not allowed error passed through ctx err := gologin.ErrorFromContext(ctx) if assert.Error(t, err) { assert.Equal(t, err, fmt.Errorf("Method not allowed")) } } ts := httptest.NewServer(ctxh.NewHandler(TokenHandler(config, assertSuccessNotCalled(t), ctxh.ContextHandlerFunc(failure)))) http.Get(ts.URL) }
// New returns a new ServeMux with app routes. func New(c *Config) *http.ServeMux { mux := http.NewServeMux() mux.Handle("/", welcomeHandler(c.DigitsConsumerKey)) mux.Handle("/profile", requireLogin(http.HandlerFunc(profileHandler))) mux.HandleFunc("/logout", logoutHandler) // 1. Register a Digits LoginHandler to receive Javascript login POST config := &digits.Config{ ConsumerKey: c.DigitsConsumerKey, } mux.Handle("/login/digits", ctxh.NewHandler(digits.LoginHandler(config, issueSession(), nil))) return mux }
func TestWebHandler_ErrorGettingRequestToken(t *testing.T) { proxyClient, server := testutils.NewErrorServer("OAuth1 Service Down", http.StatusInternalServerError) defer server.Close() config := &Config{ ConsumerKey: testConsumerKey, Client: proxyClient, } handler := LoginHandler(config, testutils.AssertSuccessNotCalled(t), nil) ts := httptest.NewServer(ctxh.NewHandler(handler)) // assert that error occurs indicating the Digits Account cound not be confirmed resp, _ := http.PostForm(ts.URL, url.Values{accountEndpointField: {testAccountEndpoint}, accountRequestHeaderField: {testAccountRequestHeader}}) testutils.AssertBodyString(t, resp.Body, ErrUnableToGetDigitsAccount.Error()+"\n") }
func TestTokenHandler_InvalidFields(t *testing.T) { config := &oauth1.Config{} handler := TokenHandler(config, testutils.AssertSuccessNotCalled(t), nil) ts := httptest.NewServer(ctxh.NewHandler(handler)) // asert errors occur for different missing POST fields resp, err := http.PostForm(ts.URL, url.Values{"wrongFieldName": {testDigitsToken}, accessTokenSecretField: {testDigitsSecret}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrMissingToken.Error()+"\n") resp, err = http.PostForm(ts.URL, url.Values{accessTokenField: {testDigitsToken}, "wrongFieldName": {testDigitsSecret}}) assert.Nil(t, err) testutils.AssertBodyString(t, resp.Body, ErrMissingTokenSecret.Error()+"\n") }
func TestLoginHandler_MissingCtxState(t *testing.T) { config := &oauth2.Config{} failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { assert.Equal(t, "oauth2: Context missing state value", err.Error()) } fmt.Fprintf(w, "failure handler called") } // LoginHandler cannot get the state from the ctx, assert that: // - failure handler is called // - error about missing state is added to the ctx loginHandler := LoginHandler(config, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) ctxh.NewHandler(loginHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }
func TestAuthRedirectHandler_MissingCtxRequestToken(t *testing.T) { config := &oauth1.Config{} failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { assert.Equal(t, "oauth1: Context missing request token or secret", err.Error()) } fmt.Fprintf(w, "failure handler called") } // CallbackHandler cannot get the request token from the ctx, assert that: // - failure handler is called // - error about missing request token is added to the ctx authRedirectHandler := AuthRedirectHandler(config, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/", nil) ctxh.NewHandler(authRedirectHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }
func TestCallbackHandler_MissingCtxState(t *testing.T) { config := &oauth2.Config{} success := testutils.AssertSuccessNotCalled(t) failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { assert.Equal(t, "oauth2: Context missing state value", err.Error()) } fmt.Fprintf(w, "failure handler called") } // CallbackHandler cannot get the state parameter from the ctx, assert that: // - failure handler is called // - error about missing state ctx param is added to the failure handler ctx callbackHandler := CallbackHandler(config, success, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/?code=any_code&state=d4e5f6", nil) ctxh.NewHandler(callbackHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }
func TestCallbackHandler_MissingCtxRequestSecret(t *testing.T) { config := &oauth1.Config{} success := testutils.AssertSuccessNotCalled(t) failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) { err := gologin.ErrorFromContext(ctx) if assert.NotNil(t, err) { assert.Equal(t, "oauth1: Context missing request token or secret", err.Error()) } fmt.Fprintf(w, "failure handler called") } // CallbackHandler cannot get the request secret from the ctx, assert that: // - failure handler is called // - error about missing request secret is added to the ctx callbackHandler := CallbackHandler(config, success, ctxh.ContextHandlerFunc(failure)) w := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/?oauth_token=any_token&oauth_verifier=any_verifier", nil) ctxh.NewHandler(callbackHandler).ServeHTTP(w, req) assert.Equal(t, "failure handler called", w.Body.String()) }