func (suite *OauthTestSuite) TestPasswordGrant() {
	// Prepare a request
	r, err := http.NewRequest("POST", "http://1.2.3.4/v1/oauth/tokens", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.SetBasicAuth("test_client_1", "test_secret")
	r.PostForm = url.Values{
		"grant_type": {"password"},
		"username":   {"test@user"},
		"password":   {"test_password"},
		"scope":      {"read_write"},
	}

	// Serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Fetch data
	accessToken, refreshToken := new(oauth.AccessToken), new(oauth.RefreshToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		Last(accessToken).RecordNotFound())
	assert.False(suite.T(), oauth.RefreshTokenPreload(suite.db).
		Last(refreshToken).RecordNotFound())

	// Check the response
	expected := &oauth.AccessTokenResponse{
		UserID:       accessToken.User.MetaUserID,
		AccessToken:  accessToken.Token,
		ExpiresIn:    3600,
		TokenType:    tokentypes.Bearer,
		Scope:        "read_write",
		RefreshToken: refreshToken.Token,
	}
	testutil.TestResponseObject(suite.T(), w, expected, 200)
}
func (suite *OauthTestSuite) TestClientCredentialsGrant() {
	// Prepare a request
	r, err := http.NewRequest("POST", "http://1.2.3.4/v1/oauth/tokens", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.SetBasicAuth("test_client_1", "test_secret")
	r.PostForm = url.Values{
		"grant_type": {"client_credentials"},
		"scope":      {"read_write"},
	}

	// Serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Fetch data
	accessToken := new(oauth.AccessToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		Last(accessToken).RecordNotFound())

	// Check the response
	expected := &oauth.AccessTokenResponse{
		AccessToken: accessToken.Token,
		ExpiresIn:   3600,
		TokenType:   tokentypes.Bearer,
		Scope:       "read_write",
	}
	testutil.TestResponseObject(suite.T(), w, expected, 200)

	// Client credentials grant does not produce refresh token
	assert.True(suite.T(), oauth.RefreshTokenPreload(suite.db).
		First(new(oauth.RefreshToken)).RecordNotFound())
}
func (suite *OauthTestSuite) TestAuthorizationCodeGrant() {
	// Insert a test authorization code
	err := suite.db.Create(&oauth.AuthorizationCode{
		Code:        "test_code",
		ExpiresAt:   time.Now().UTC().Add(+10 * time.Second),
		Client:      suite.clients[0],
		User:        suite.users[0],
		RedirectURI: util.StringOrNull("https://www.example.com"),
		Scope:       "read_write",
	}).Error
	assert.NoError(suite.T(), err, "Inserting test data failed")

	// Prepare a request
	r, err := http.NewRequest("POST", "http://1.2.3.4/v1/oauth/tokens", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.SetBasicAuth("test_client_1", "test_secret")
	r.PostForm = url.Values{
		"grant_type":   {"authorization_code"},
		"code":         {"test_code"},
		"redirect_uri": {"https://www.example.com"},
	}

	// Serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Fetch data
	accessToken, refreshToken := new(oauth.AccessToken), new(oauth.RefreshToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		Last(accessToken).RecordNotFound())
	assert.False(suite.T(), oauth.RefreshTokenPreload(suite.db).
		Last(refreshToken).RecordNotFound())

	// Check the response
	expected := &oauth.AccessTokenResponse{
		UserID:       accessToken.User.MetaUserID,
		AccessToken:  accessToken.Token,
		ExpiresIn:    3600,
		TokenType:    tokentypes.Bearer,
		Scope:        "read_write",
		RefreshToken: refreshToken.Token,
	}
	testutil.TestResponseObject(suite.T(), w, expected, 200)

	// The authorization code should get deleted after use
	assert.True(suite.T(), suite.db.Unscoped().
		First(new(oauth.AuthorizationCode)).RecordNotFound())
}
func (suite *OauthTestSuite) TestGetOrCreateRefreshTokenCreatesNew() {
	var (
		refreshToken *oauth.RefreshToken
		err          error
		tokens       []*oauth.RefreshToken
	)

	// Since there is no user specific token,
	// a new one should be created and returned
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		suite.users[0],   // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db).Order("id").Find(&tokens)

		// There should be just one token now
		assert.Equal(suite.T(), 1, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[0].Token, refreshToken.Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[0].ClientID.Valid)
		assert.Equal(suite.T(), suite.clients[0].ID, tokens[0].Client.ID)

		// User ID should be set
		assert.True(suite.T(), tokens[0].UserID.Valid)
		assert.Equal(suite.T(), suite.users[0].ID, tokens[0].User.ID)
	}

	// Valid user specific token exists, new one should NOT be created
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		suite.users[0],   // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db).Order("id").Find(&tokens)

		// There should be just one token now
		assert.Equal(suite.T(), 1, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[0].Token, refreshToken.Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[0].ClientID.Valid)
		assert.Equal(suite.T(), suite.clients[0].ID, tokens[0].Client.ID)

		// User ID should be set
		assert.True(suite.T(), tokens[0].UserID.Valid)
		assert.Equal(suite.T(), suite.users[0].ID, tokens[0].User.ID)
	}

	// Since there is no client only token,
	// a new one should be created and returned
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		nil,              // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db).Order("id").Find(&tokens)

		// There should be 2 tokens
		assert.Equal(suite.T(), 2, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[1].Token, refreshToken.Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[1].ClientID.Valid)
		assert.Equal(suite.T(), suite.clients[0].ID, tokens[1].Client.ID)

		// User ID should be nil
		assert.False(suite.T(), tokens[1].UserID.Valid)
	}

	// Valid client only token exists, new one should NOT be created
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		nil,              // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db).Order("id").Find(&tokens)

		// There should be 2 tokens
		assert.Equal(suite.T(), 2, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[1].Token, refreshToken.Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[1].ClientID.Valid)
		assert.Equal(suite.T(), suite.clients[0].ID, tokens[1].Client.ID)

		// User ID should be nil
		assert.False(suite.T(), tokens[1].UserID.Valid)
	}
}
func (suite *OauthTestSuite) TestGetOrCreateRefreshTokenDeletesExpired() {
	var (
		refreshToken *oauth.RefreshToken
		err          error
		tokens       []*oauth.RefreshToken
	)

	// Insert an expired client only test refresh token
	err = suite.db.Create(&oauth.RefreshToken{
		Token:     "test_token",
		ExpiresAt: time.Now().UTC().Add(-10 * time.Second),
		Client:    suite.clients[0],
	}).Error
	assert.NoError(suite.T(), err, "Inserting test data failed")

	// Since the current client only token is expired,
	// this should delete it and create and return a new one
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		nil,              // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db.Unscoped()).Order("id").Find(&tokens)

		// There should be just one token right now
		assert.Equal(suite.T(), 1, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[0].Token, refreshToken.Token)
		assert.NotEqual(suite.T(), "test_token", refreshToken.Token)
		assert.NotEqual(suite.T(), "test_token", tokens[0].Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[0].ClientID.Valid)
		assert.Equal(suite.T(), int64(suite.clients[0].ID), tokens[0].ClientID.Int64)

		// User ID should be nil
		assert.False(suite.T(), tokens[0].UserID.Valid)
	}

	// Insert an expired user specific test refresh token
	err = suite.db.Create(&oauth.RefreshToken{
		Token:     "test_token",
		ExpiresAt: time.Now().UTC().Add(-10 * time.Second),
		Client:    suite.clients[0],
		User:      suite.users[0],
	}).Error
	assert.NoError(suite.T(), err, "Inserting test data failed")

	// Since the current user specific token is expired,
	// this should delete it and create and return a new one
	refreshToken, err = suite.service.GetOrCreateRefreshToken(
		suite.clients[0], // client
		suite.users[0],   // user
		3600,             // expires in
		"read_write",     // scope
	)

	// Error should be nil
	if assert.Nil(suite.T(), err) {
		// Fetch all refresh tokens
		oauth.RefreshTokenPreload(suite.db.Unscoped()).Order("id").Find(&tokens)

		// There should be 2 tokens now
		assert.Equal(suite.T(), 2, len(tokens))

		// Correct refresh token object should be returned
		assert.NotNil(suite.T(), refreshToken)
		assert.Equal(suite.T(), tokens[1].Token, refreshToken.Token)
		assert.NotEqual(suite.T(), "test_token", refreshToken.Token)
		assert.NotEqual(suite.T(), "test_token", tokens[1].Token)

		// Client ID should be set
		assert.True(suite.T(), tokens[1].ClientID.Valid)
		assert.Equal(suite.T(), int64(suite.clients[0].ID), tokens[1].ClientID.Int64)

		// User ID should be set
		assert.True(suite.T(), tokens[1].UserID.Valid)
		assert.Equal(suite.T(), int64(suite.users[0].ID), tokens[1].UserID.Int64)
	}
}
func (suite *AccountsTestSuite) TestConfirmEmailWithAutologinFlag() {
	var (
		testOauthUser    *oauth.User
		testUser         *accounts.User
		testConfirmation *accounts.Confirmation
		err              error
	)

	// Insert a test user
	testOauthUser, err = suite.service.GetOauthService().CreateUser(
		roles.User,
		"harold@finch",
		"test_password",
	)
	assert.NoError(suite.T(), err, "Failed to insert a test oauth user")
	testUser, err = accounts.NewUser(
		suite.accounts[0],
		testOauthUser,
		"",    //facebook ID
		false, // confirmed
		&accounts.UserRequest{
			FirstName: "Harold",
			LastName:  "Finch",
		},
	)
	assert.NoError(suite.T(), err, "Failed to create a new user object")
	err = suite.db.Create(testUser).Error
	assert.NoError(suite.T(), err, "Failed to insert a test user")
	testUser.Account = suite.accounts[0]

	// Insert a test confirmation
	testConfirmation, err = accounts.NewConfirmation(
		testUser,
		suite.cnf.AppSpecific.ConfirmationLifetime,
	)
	assert.NoError(suite.T(), err, "Failed to create a new confirmation object")
	err = suite.db.Create(testConfirmation).Error
	assert.NoError(suite.T(), err, "Failed to insert a test confirmation")
	testConfirmation.User = testUser

	// Prepare a request
	r, err := http.NewRequest(
		"GET",
		fmt.Sprintf(
			"http://1.2.3.4/v1/confirmations/%s?autologin=true",
			testConfirmation.Reference,
		),
		nil,
	)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.Header.Set(
		"Authorization",
		fmt.Sprintf(
			"Basic %s",
			b64.StdEncoding.EncodeToString([]byte("test_client_1:test_secret")),
		),
	)

	// Check the routing
	match := new(mux.RouteMatch)
	suite.router.Match(r, match)
	if assert.NotNil(suite.T(), match.Route) {
		assert.Equal(suite.T(), "confirm_email", match.Route.GetName())
	}

	// Count before
	var (
		countBefore              int
		accessTokensCountBefore  int
		refreshTokensCountBefore int
	)
	suite.db.Model(new(accounts.Confirmation)).Count(&countBefore)
	suite.db.Model(new(oauth.AccessToken)).Count(&accessTokensCountBefore)
	suite.db.Model(new(oauth.RefreshToken)).Count(&refreshTokensCountBefore)

	// And serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Count after
	var (
		countAfter              int
		accessTokensCountAfter  int
		refreshTokensCountAfter int
	)
	suite.db.Model(new(accounts.Confirmation)).Count(&countAfter)
	suite.db.Model(new(oauth.AccessToken)).Count(&accessTokensCountAfter)
	suite.db.Model(new(oauth.RefreshToken)).Count(&refreshTokensCountAfter)
	assert.Equal(suite.T(), countBefore-1, countAfter)
	assert.Equal(suite.T(), accessTokensCountBefore+1, accessTokensCountAfter)
	assert.Equal(suite.T(), refreshTokensCountBefore+1, refreshTokensCountAfter)

	// Fetch the updated user
	user := new(accounts.User)
	notFound := accounts.UserPreload(suite.db).First(user, testUser.ID).RecordNotFound()
	assert.False(suite.T(), notFound)

	// Confirmation should have been soft deleteted
	assert.True(suite.T(), suite.db.Last(new(accounts.Confirmation)).RecordNotFound())

	// And correct data was saved
	assert.True(suite.T(), user.Confirmed)

	// Fetch login data
	accessToken, refreshToken := new(oauth.AccessToken), new(oauth.RefreshToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		Last(accessToken).RecordNotFound())
	assert.False(suite.T(), oauth.RefreshTokenPreload(suite.db).
		Last(refreshToken).RecordNotFound())

	// Check the response
	expectedEmbeddedTokenResponse, err := oauth.NewAccessTokenResponse(
		accessToken,
		refreshToken,
		suite.cnf.Oauth.AccessTokenLifetime,
		tokentypes.Bearer,
	)
	assert.NoError(suite.T(), err, "Failed to create expected response object")
	expected, err := accounts.NewConfirmationResponse(testConfirmation)
	expected.SetEmbedded(
		"access-token",
		jsonhal.Embedded(expectedEmbeddedTokenResponse),
	)
	assert.NoError(suite.T(), err, "Failed to create expected response object")
	testutil.TestResponseObject(suite.T(), w, expected, 200)
}
func (suite *FacebookTestSuite) TestLoginCreatesNewUserNoPicture() {
	// Prepare a request
	r, err := http.NewRequest("POST", "http://1.2.3.4/v1/facebook/login", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.PostForm = url.Values{
		"access_token": {"facebook_token"},
		"scope":        {"read_write"},
	}
	r.SetBasicAuth("test_client_1", "test_secret")

	// Check the routing
	match := new(mux.RouteMatch)
	suite.router.Match(r, match)
	if assert.NotNil(suite.T(), match.Route) {
		assert.Equal(suite.T(), "facebook_login", match.Route.GetName())
	}

	// Mock fetching profile data from facebook
	suite.mockFacebookGetMe(fb.Result{
		"id":         "new_facebook_id",
		"email":      "new@user",
		"name":       "John Reese",
		"first_name": "John",
		"last_name":  "Reese",
		"picture":    nil,
	}, nil)

	// Count before
	var countBefore int
	suite.db.Model(new(accounts.User)).Count(&countBefore)

	// And serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Check mock expectations were met
	suite.adapterMock.AssertExpectations(suite.T())

	// Check the status code
	if !assert.Equal(suite.T(), 200, w.Code) {
		log.Print(w.Body.String())
	}

	// Count after
	var countAfter int
	suite.db.Model(new(accounts.User)).Count(&countAfter)
	assert.Equal(suite.T(), countBefore+1, countAfter)

	// Fetch the created user
	user := new(accounts.User)
	notFound := accounts.UserPreload(suite.db).
		Last(user).RecordNotFound()
	assert.False(suite.T(), notFound)

	// And correct data was saved
	assert.Equal(suite.T(), user.ID, user.OauthUser.MetaUserID)
	assert.Equal(suite.T(), "new@user", user.OauthUser.Username)
	assert.Equal(suite.T(), "John", user.FirstName.String)
	assert.Equal(suite.T(), "Reese", user.LastName.String)
	assert.Equal(suite.T(), "new_facebook_id", user.FacebookID.String)
	assert.False(suite.T(), user.Picture.Valid)
	assert.Equal(suite.T(), roles.User, user.OauthUser.RoleID.String)

	// Fetch oauth tokens
	accessToken := new(oauth.AccessToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		First(accessToken).RecordNotFound())
	refreshToken := new(oauth.RefreshToken)
	assert.False(suite.T(), oauth.RefreshTokenPreload(suite.db).
		First(refreshToken).RecordNotFound())

	// Check the response body
	expected, err := json.Marshal(&oauth.AccessTokenResponse{
		UserID:       user.ID,
		AccessToken:  accessToken.Token,
		ExpiresIn:    3600,
		TokenType:    tokentypes.Bearer,
		Scope:        "read_write",
		RefreshToken: refreshToken.Token,
	})
	if assert.NoError(suite.T(), err, "JSON marshalling failed") {
		assert.Equal(suite.T(), string(expected), strings.TrimSpace(w.Body.String()))
	}
}
func (suite *FacebookTestSuite) TestLoginUpdatesExistingUser() {
	var (
		testOauthUser *oauth.User
		testUser      *accounts.User
		err           error
	)

	// Insert a test user
	testOauthUser, err = suite.service.GetAccountsService().GetOauthService().CreateUser(
		roles.User,
		"harold@finch",
		"", // empty password
	)
	assert.NoError(suite.T(), err, "Failed to insert a test oauth user")
	testUser, err = accounts.NewUser(
		suite.accounts[0],
		testOauthUser,
		"some_facebook_id", // facebook ID
		true,               // confirmed
		&accounts.UserRequest{
			FirstName: "Harold",
			LastName:  "Finch",
			Picture:   "some_picture",
		},
	)
	assert.NoError(suite.T(), err, "Failed to create a new test account user object")
	err = suite.db.Create(testUser).Error
	assert.NoError(suite.T(), err, "Failed to insert a test user")
	testUser.OauthUser = testOauthUser

	// Prepare a request
	r, err := http.NewRequest("POST", "http://1.2.3.4/v1/facebook/login", nil)
	assert.NoError(suite.T(), err, "Request setup should not get an error")
	r.PostForm = url.Values{
		"access_token": {"facebook_token"},
		"scope":        {"read_write"},
	}
	r.SetBasicAuth("test_client_1", "test_secret")

	// Check the routing
	match := new(mux.RouteMatch)
	suite.router.Match(r, match)
	if assert.NotNil(suite.T(), match.Route) {
		assert.Equal(suite.T(), "facebook_login", match.Route.GetName())
	}

	// Mock fetching profile data from facebook
	suite.mockFacebookGetMe(fb.Result{
		"id":         "new_facebook_id",
		"email":      testUser.OauthUser.Username,
		"name":       "New Name",
		"first_name": "New First Name",
		"last_name":  "New Last Name",
		"picture": map[string]interface{}{
			"data": map[string]interface{}{
				"url": "new_picture",
			},
		},
	}, nil)

	// Count before
	var countBefore int
	suite.db.Model(new(accounts.User)).Count(&countBefore)

	// And serve the request
	w := httptest.NewRecorder()
	suite.router.ServeHTTP(w, r)

	// Check mock expectations were met
	suite.adapterMock.AssertExpectations(suite.T())

	// Check the status code
	if !assert.Equal(suite.T(), 200, w.Code) {
		log.Print(w.Body.String())
	}

	// Count after
	var countAfter int
	suite.db.Model(new(accounts.User)).Count(&countAfter)
	assert.Equal(suite.T(), countBefore, countAfter)

	// Fetch the updated user
	user := new(accounts.User)
	notFound := accounts.UserPreload(suite.db).
		First(user, testUser.ID).RecordNotFound()
	assert.False(suite.T(), notFound)

	// And correct data was saved
	assert.Equal(suite.T(), testUser.OauthUser.Username, user.OauthUser.Username)
	assert.Equal(suite.T(), "New First Name", user.FirstName.String)
	assert.Equal(suite.T(), "New Last Name", user.LastName.String)
	assert.Equal(suite.T(), "new_facebook_id", user.FacebookID.String)
	assert.Equal(suite.T(), "new_picture", user.Picture.String)
	assert.Equal(suite.T(), roles.User, user.OauthUser.RoleID.String)

	// Fetch oauth tokens
	accessToken := new(oauth.AccessToken)
	assert.False(suite.T(), oauth.AccessTokenPreload(suite.db).
		First(accessToken).RecordNotFound())
	refreshToken := new(oauth.RefreshToken)
	assert.False(suite.T(), oauth.RefreshTokenPreload(suite.db).
		First(refreshToken).RecordNotFound())

	// Check the response body
	expected, err := json.Marshal(&oauth.AccessTokenResponse{
		UserID:       user.ID,
		AccessToken:  accessToken.Token,
		ExpiresIn:    3600,
		TokenType:    tokentypes.Bearer,
		Scope:        "read_write",
		RefreshToken: refreshToken.Token,
	})
	if assert.NoError(suite.T(), err, "JSON marshalling failed") {
		assert.Equal(suite.T(), string(expected), strings.TrimSpace(w.Body.String()))
	}
}