public async Task ValidateAsync(ExtensionGrantValidationContext context) { try { var token = context.Request.Raw["token"]; var userId = await GetFacebookUserIdFromTokenAsync(context, token); if (userId == null) { return; } _logger.LogDebug("FacebookSignIn: Signing in: {0}", userId); User user = await GetOrCreateUserAsync(userId); var claims = await _userClaimsProvider.GetUserClaimsAsync(user); context.Result = new GrantValidationResult(user.UserId, "nether-facebook", claims); _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> { { "LoginType", "fb-usertoken" } }); } catch (Exception ex) { _logger.LogError("Error in ValidateAsync: {0}", ex); _appMonitor.LogError(ex, "Error in ValidateAsync", new Dictionary <string, string> { { "EventType", "LoginFailed" }, { "EventSubType", "UnhandledException" }, { "LoginType", "fb-usertoken" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, ex.Message); } }
public async Task <IActionResult> SetGamertagForPlayerId( [FromRoute] string playerid, [FromBody] SetGamertagRequestModel model) { var player = await _store.GetPlayerDetailsByUserIdAsync(playerid); if (player == null) { player = new Player { UserId = playerid }; } if (!string.IsNullOrEmpty(player.Gamertag)) { _logger.LogInformation("Player already has gamertag (cannot update) in SetGamertagForPlayerId"); _appMonitor.LogEvent("RegisterFailed", properties: new Dictionary <string, string> { { "Reason", "UserAlreadyHasGamertag" }, { "Source", "Interactive" } }); return(this.ValidationFailed(new ErrorDetail("gamertag", "Cannot update gamertag"))); } player.Gamertag = model.Gamertag; await _store.SavePlayerAsync(player); _appMonitor.LogEvent("RegisterSucceeded", properties: new Dictionary <string, string> { { "Reason", "UserAlreadyHasGamertag" }, { "Source", "Interactive" } }); return(Ok()); }
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { var userName = context.UserName; var user = await _userStore.GetUserByLoginAsync(LoginProvider.UserNamePassword, userName); if (user == null) { _logger.LogTrace("User not found: '{0}'", userName); _appMonitor.LogEvent("LoginFailed", "ResourceOwner: user not found", new Dictionary <string, string> { { "EventSubType", "UserNotFound" }, { "LoginType", "password" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); return; } if (!user.IsActive) { _logger.LogTrace("User inactive: '{0}'", userName); _appMonitor.LogEvent("LoginFailed", "ResourceOwner: user inactive", new Dictionary <string, string> { { "EventSubType", "UserInactive" }, { "LoginType", "password" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); return; } var login = user.Logins.FirstOrDefault(l => l.ProviderType == LoginProvider.UserNamePassword); if (login == null) { // shouldn't get here! _logger.LogError("User does not have a username password login entry: '{0}'", userName); _appMonitor.LogEvent("LoginFailed", "ResourceOwner: user has no password login entry", new Dictionary <string, string> { { "EventSubType", "UserHasNoPassword" }, { "LoginType", "password" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); } bool valid = _passwordHasher.VerifyHashedPassword( hashedPassword: login.ProviderData, providedPassword: context.Password); if (!valid) { context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); return; } var claims = await _userClaimsProvider.GetUserClaimsAsync(user); context.Result = new GrantValidationResult(user.UserId, "password", claims); _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> { { "LoginType", "password" } }); }
public async Task ValidateAsync(ExtensionGrantValidationContext context) { try { var token = context.Request.Raw["token"]; var facebookTokenDebug = await _facebookGraphService.TokenDebugAsync(token); if (!facebookTokenDebug.IsValid) { var message = (string)facebookTokenDebug.Error.Message; _logger.LogError("FacebookSignIn: invalid token: {0}", message); _appMonitor.LogEvent("LoginFailed", $"FacebookSignIn: invalid token: {message}", new Dictionary <string, string> { { "EventSubType", "InvalidToken" }, { "LoginType", "fb-usertoken" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); return; } if (facebookTokenDebug.Error != null) // still got another error { var message = (string)facebookTokenDebug.Error.Message; _logger.LogError("FacebookSignIn: error validating token: {0}", message); _appMonitor.LogEvent("LoginFailed", $"FacebookSignIn: error validating token: {message}", new Dictionary <string, string> { { "EventSubType", "TokenValidationFailed" }, { "LoginType", "fb-usertoken" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest); return; } var userId = facebookTokenDebug.UserId; if (userId == null) { return; } _logger.LogDebug("FacebookSignIn: Signing in: {0}", userId); User user = await GetOrCreateUserAsync(userId); var claims = await _userClaimsProvider.GetUserClaimsAsync(user); context.Result = new GrantValidationResult(user.UserId, "nether-facebook", claims); _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> { { "LoginType", "fb-usertoken" } }); } catch (Exception ex) { _logger.LogError("Error in ValidateAsync: {0}", ex); _appMonitor.LogError(ex, "Error in ValidateAsync", new Dictionary <string, string> { { "EventType", "LoginFailed" }, { "EventSubType", "UnhandledException" }, { "LoginType", "fb-usertoken" } }); context.Result = new GrantValidationResult(TokenRequestErrors.InvalidRequest, ex.Message); } }
public async Task <IActionResult> Login(LoginInputModel model) { if (ModelState.IsValid) { // validate username/password against in-memory store var validationContext = new ResourceOwnerPasswordValidationContext { UserName = model.Username, Password = model.Password }; await _passwordValidator.ValidateAsync(validationContext); if (!validationContext.Result.IsError) { AuthenticationProperties props = null; // only set explicit expiration here if persistent. // otherwise we reply upon expiration configured in cookie middleware. if (AccountOptions.AllowRememberLogin && model.RememberLogin) { props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration) }; } ; // issue authentication cookie with subject ID and username var user = await _userStore.GetUserByLoginAsync(LoginProvider.UserNamePassword, model.Username); var userId = user.UserId; await HttpContext.Authentication.SignInAsync(userId, model.Username, props); _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> { { "LoginType", "interactive" }, { "LoginSubType", "local" } }); // make sure the returnUrl is still valid, and if yes - redirect back to authorize endpoint if (_interaction.IsValidReturnUrl(model.ReturnUrl)) { return(Redirect(model.ReturnUrl)); } return(Redirect("~/")); } ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage); } // something went wrong, show form with error var vm = await _account.BuildLoginViewModelAsync(model); return(View(vm)); }
public async Task <IActionResult> Get(string name) { var gamertag = User.GetGamerTag(); _appMonitor.LogEvent("Leaderboard", properties: new Dictionary <string, string> { { "Name", name } }); LeaderboardConfig config = _leaderboardProvider.GetByName(name); if (config == null) { return(NotFound()); } LeaderboardType type = config.Type; List <GameScore> scores; switch (type) { case LeaderboardType.AroundMe: if (gamertag == null) { return(this.ValidationFailed(new ErrorDetail("gamertag", "Must be signed in as a player with a gamertag to retrive this leaderboard"))); } scores = await _store.GetScoresAroundMeAsync(gamertag, config.Radius); break; case LeaderboardType.Top: scores = await _store.GetTopHighScoresAsync(config.Top); break; default: scores = await _store.GetAllHighScoresAsync(); break; } GameScore currentPlayer = null; if (config.IncludeCurrentPlayer && gamertag != null) { currentPlayer = (await _store.GetScoresAroundMeAsync(gamertag, 0)).FirstOrDefault(); } // Format response model var resultModel = new LeaderboardGetResponseModel { Entries = scores ?.Select(s => LeaderboardGetResponseModel.LeaderboardEntry.Map(s, gamertag)) ?.ToList(), CurrentPlayer = LeaderboardGetResponseModel.LeaderboardEntry.Map(currentPlayer, null) }; // Return result return(Ok(resultModel)); }
public async Task <IActionResult> Post([FromBody] ScorePostRequestModel request) { //TODO: Make validation more sophisticated, perhaps some games want/need negative scores // Validate input if (request.Score < 0) { _logger.LogError("score is negative ({0})", request.Score); _appMonitor.LogEvent("InvalidScore", properties: new Dictionary <string, string> { { "Score", request.Score.ToString() } }); return(this.ValidationFailed(new ErrorDetail("score", "Score cannot be negative"))); } //TODO: Handle exceptions and retries var gamertag = User.GetGamerTag(); if (string.IsNullOrWhiteSpace(gamertag)) { _logger.LogError("User has no gamertag: '{0}'", User.GetId()); return(this.ValidationFailed(new ErrorDetail("gamertag", "The user doesn't have a gamertag"))); } var userId = User.GetId(); // Save score and call analytics in parallel await Task.WhenAll( _store.SaveScoreAsync(new GameScore { UserId = userId, Country = request.Country, Score = request.Score }), SendScoreEventAndLogErrors(request)); _appMonitor.LogEvent("Score", properties: new Dictionary <string, string> { { "Score", request.Score.ToString() } }); // Return result return(Ok()); }
public async Task <IActionResult> PutCurrentPlayer([FromBody] PlayerPutRequestModel player) { string userId = User.GetId(); bool newPlayer = false; var playerEntity = await _store.GetPlayerDetailsByUserIdAsync(userId); if (playerEntity == null) { newPlayer = true; if (player.Gamertag != null) { // check if gamertag is already in use var existingPlayerForGamertag = await _store.GetPlayerDetailsByUserIdAsync(player.Gamertag); if (existingPlayerForGamertag != null && existingPlayerForGamertag.UserId != userId) { // Can't use a gamertag from another user return(this.ValidationFailed(new ErrorDetail("gamertag", "Gamertag already in use"))); } } playerEntity = new Player { UserId = userId, Gamertag = player.Gamertag, Country = player.Country, CustomTag = player.CustomTag }; } else { if (playerEntity.Gamertag != player.Gamertag) { // can't change gamertag return(this.ValidationFailed(new ErrorDetail("gamertag", "Can't change gamertag"))); } playerEntity.Country = player.Country; playerEntity.CustomTag = player.CustomTag; } // Update player await _store.SavePlayerAsync(playerEntity); // is this a new player registration? if (newPlayer) { _appMonitor.LogEvent("Register"); } // Return result return(NoContent()); }
public async Task ValidateAsync(ExtensionGrantValidationContext context) { var guestIdentifier = context.Request.Raw["guest_identifier"]; _logger.LogInformation("GuestAccessToken: Signing in with guest access token '{0}'", guestIdentifier); User user = await GetOrCreateGuestUserAsync(guestIdentifier); var claims = await _userClaimsProvider.GetUserClaimsAsync(user); context.Result = new GrantValidationResult(user.UserId, "nether-guest", claims); _appMonitor.LogEvent("LoginSucceeded", properties: new Dictionary <string, string> { { "LoginType", "guest-access" } }); }
public async Task <IActionResult> Get(string name) { var userId = User.GetId(); _appMonitor.LogEvent("Leaderboard", properties: new Dictionary <string, string> { { "Name", name } }); LeaderboardConfig config = _leaderboardProvider.GetByName(name); if (config == null) { return(NotFound()); } LeaderboardType type = config.Type; List <GameScore> scores; switch (type) { case LeaderboardType.AroundMe: if (userId == null) { return(this.ValidationFailed(new ErrorDetail("userId", "Must be signed in as a player with a userId to retrive this leaderboard"))); } scores = await _store.GetScoresAroundUserAsync(userId, config.Radius); break; case LeaderboardType.Top: scores = await _store.GetTopHighScoresAsync(config.Top); break; default: scores = await _store.GetAllHighScoresAsync(); break; } var userIdsToLookUp = scores.Select(s => s.UserId).ToList(); GameScore currentPlayer = null; if (config.IncludeCurrentPlayer && userId != null) { currentPlayer = (await _store.GetScoresAroundUserAsync(userId, 0)).FirstOrDefault(); if (currentPlayer != null && !userIdsToLookUp.Contains(currentPlayer.UserId)) { userIdsToLookUp.Add(currentPlayer.UserId); } } var gamertags = await _playerManagementClient.GetGamertagsForUserIdsAsync(userIdsToLookUp.ToArray()); var resultModel = new LeaderboardGetResponseModel { Entries = scores ?.Select(s => Map(s, userId)) ?.ToList(), CurrentPlayer = Map(currentPlayer, null) }; return(Ok(resultModel)); // local function to map to response types LeaderboardGetResponseModel.LeaderboardEntry Map(GameScore score, string currentUserId) { if (score == null) { return(null); } //find gamertag for userid return(new LeaderboardGetResponseModel.LeaderboardEntry { Gamertag = gamertags.Single(g => g.UserId == score.UserId).Gamertag, Score = score.Score, Rank = score.Rank, IsCurrentPlayer = currentUserId == score.UserId }); } }