func TestGetAuthenticatedAccount(t *testing.T) {
	var (
		account *accounts.Account
		err     error
	)

	// A test request
	r, err := http.NewRequest("GET", "http://1.2.3.4/something", nil)
	assert.NoError(t, err, "Request setup should not get an error")

	account, err = accounts.GetAuthenticatedAccount(r)

	// Account object should be nil
	assert.Nil(t, account)

	// Correct error should be returned
	if assert.NotNil(t, err) {
		assert.Equal(t, accounts.ErrAccountAuthenticationRequired, err)
	}

	// Set a context value of an invalid type
	context.Set(r, accounts.AuthenticatedAccountKey, "bogus")

	account, err = accounts.GetAuthenticatedAccount(r)

	// Account object should be nil
	assert.Nil(t, account)

	// Correct error should be returned
	if assert.NotNil(t, err) {
		assert.Equal(t, accounts.ErrAccountAuthenticationRequired, err)
	}

	// Set a valid context value
	context.Set(r, accounts.AuthenticatedAccountKey, &accounts.Account{Name: "Test Account"})

	account, err = accounts.GetAuthenticatedAccount(r)

	// Error should be nil
	assert.Nil(t, err)

	// Correct account object should be returned
	if assert.NotNil(t, account) {
		assert.Equal(t, "Test Account", account.Name)
	}
}
func (suite *AccountsTestSuite) TestAccountAuthMiddleware() {
	var (
		r                    *http.Request
		w                    *httptest.ResponseRecorder
		next                 http.HandlerFunc
		authenticatedAccount *accounts.Account
		err                  error
	)

	middleware := accounts.NewAccountAuthMiddleware(suite.service)

	// Send a request without basic auth through the middleware
	r, err = http.NewRequest("POST", "http://1.2.3.4/something", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	w = httptest.NewRecorder()
	next = func(w http.ResponseWriter, r *http.Request) {}
	middleware.ServeHTTP(w, r, next)

	// Check the response
	testutil.TestResponseForError(
		suite.T(),
		w,
		accounts.ErrAccountAuthenticationRequired.Error(),
		401,
	)

	// Check the context variable has not been set
	authenticatedAccount, err = accounts.GetAuthenticatedAccount(r)
	assert.Nil(suite.T(), authenticatedAccount)
	assert.Error(suite.T(), err)
	assert.Equal(suite.T(), accounts.ErrAccountAuthenticationRequired, err)

	// Send a request with incorrect basic auth through the middleware
	r, err = http.NewRequest("POST", "http://1.2.3.4/something", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.SetBasicAuth("bogus", "bogus")
	w = httptest.NewRecorder()
	next = func(w http.ResponseWriter, r *http.Request) {}
	middleware.ServeHTTP(w, r, next)

	// Check the response
	testutil.TestResponseForError(
		suite.T(),
		w,
		accounts.ErrAccountAuthenticationRequired.Error(),
		401,
	)

	// Check the context variable has not been set
	authenticatedAccount, err = accounts.GetAuthenticatedAccount(r)
	assert.Nil(suite.T(), authenticatedAccount)
	assert.Error(suite.T(), err)
	assert.Equal(suite.T(), accounts.ErrAccountAuthenticationRequired, err)

	// Send a request with correct basic auth through the middleware
	r, err = http.NewRequest("POST", "http://1.2.3.4/something", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.SetBasicAuth("test_client_1", "test_secret")
	w = httptest.NewRecorder()
	next = func(w http.ResponseWriter, r *http.Request) {}
	middleware.ServeHTTP(w, r, next)

	// Check the status code
	assert.Equal(suite.T(), 200, w.Code)

	// Check the context variable has been set
	authenticatedAccount, err = accounts.GetAuthenticatedAccount(r)
	assert.NoError(suite.T(), err)
	assert.NotNil(suite.T(), authenticatedAccount)
	assert.Equal(suite.T(), "Test Account 1", authenticatedAccount.Name)
	assert.Equal(suite.T(), "test_client_1", authenticatedAccount.OauthClient.Key)

	// Send a request with correct client access token as bearer
	r, err = http.NewRequest("POST", "http://1.2.3.4/something", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.Header.Set("Authorization", "Bearer test_client_token")
	w = httptest.NewRecorder()
	next = func(w http.ResponseWriter, r *http.Request) {}
	middleware.ServeHTTP(w, r, next)

	// Check the status code
	assert.Equal(suite.T(), 200, w.Code)

	// Check the context variable has been set
	authenticatedAccount, err = accounts.GetAuthenticatedAccount(r)
	assert.NoError(suite.T(), err)
	assert.NotNil(suite.T(), authenticatedAccount)
	assert.Equal(suite.T(), "Test Account 1", authenticatedAccount.Name)
	assert.Equal(suite.T(), "test_client_1", authenticatedAccount.OauthClient.Key)
}
Beispiel #3
0
// Handlers requests to login with Facebook access token
// (POST /v1/facebook/login)
func (s *Service) loginHandler(w http.ResponseWriter, r *http.Request) {
	// Get the authenticated account from the request context
	authenticatedAccount, err := accounts.GetAuthenticatedAccount(r)
	if err != nil {
		response.UnauthorizedError(w, err.Error())
		return
	}

	// Parse the form so r.Form becomes available
	if err = r.ParseForm(); err != nil {
		response.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Get the scope string
	scope, err := s.GetAccountsService().GetOauthService().GetScope(r.Form.Get("scope"))
	if err != nil {
		response.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Fetch the user data from facebook
	resp, err := s.adapter.GetMe(r.Form.Get("access_token"))
	if err != nil {
		response.UnauthorizedError(w, err.Error())
		return
	}

	// Initialise variables
	var (
		profile UserProfile
		user    *accounts.User
	)

	// Decode the response to struct
	if err = resp.Decode(&profile); err != nil {
		response.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if profile.Email == nil {
		// There is an edge case where Facebook does not return a valid email
		// User could have registered with a phone number or have an unconfirmed
		// email address. In such rare case, default to {facebook_id}@facebook.com
		edgeCaseEmail := fmt.Sprintf("*****@*****.**", profile.ID)
		profile.Email = &edgeCaseEmail
	}

	// Build user request object
	userRequest := &accounts.UserRequest{
		Email:     *profile.Email,
		FirstName: profile.FirstName,
		LastName:  profile.LastName,
		Picture:   profile.GetPictureURL(),
	}

	// Get or create a new user based on facebook ID and other details
	user, err = s.GetAccountsService().GetOrCreateFacebookUser(
		authenticatedAccount,
		profile.ID,
		userRequest,
	)
	if err != nil {
		response.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Check that the same account is being used
	if authenticatedAccount.ID != user.Account.ID {
		response.UnauthorizedError(w, ErrAccountMismatch.Error())
		return
	}

	// Log in the user
	accessToken, refreshToken, err := s.GetAccountsService().GetOauthService().Login(
		user.Account.OauthClient,
		user.OauthUser,
		scope,
	)
	if err != nil {
		response.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Write the JSON access token to the response
	accessTokenRespone := &oauth.AccessTokenResponse{
		UserID:       user.ID,
		AccessToken:  accessToken.Token,
		ExpiresIn:    s.cnf.Oauth.AccessTokenLifetime,
		TokenType:    tokentypes.Bearer,
		Scope:        accessToken.Scope,
		RefreshToken: refreshToken.Token,
	}
	response.WriteJSON(w, accessTokenRespone, 200)
}