public BearerAuthenticationProvider(WeakCache cache) { ThrowNullArguments(() => cache); _cache = cache; //make sure a logon hasnt been invalidated! OnValidateIdentity = context => Task.Run(() => { var token = context.Request.Headers.Get("Authorization").TrimStart("Bearer").Trim(); //in future, a realtime event will notify the bearer-provider of changes to a logon, so we dont need to keep quering the database var logon = _cache.GetOrRefresh <UserLogon>(token); //Note that if "logon"' is null, it means that it was not found either in the cache or in the db - but the fact that this method was called //means that the token was verified by the authorization server: this is an anomaly, as the source of the token is in question. What we do //is reject this request. if (logon?.Invalidated ?? true) { context.Rejected(); } //implement traditional session timeout after "WebConstants.Misc_SessionTimeoutMinutes" minutes else if ((DateTime.Now - logon.ModifiedOn) >= TimeSpan.FromMinutes(WebConstants.Misc_SessionTimeoutMinutes)) { logon.ModifiedOn = DateTime.Now; context.Rejected(); } else { context.OwinContext.Environment[WebConstants.Misc_UserLogonOwinContextKey] = logon; context.Validated(); } }); }
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) => Task.Run(() => { var _credentialAuthority = context.OwinContext.GetPerRequestValue <ICredentialAuthentication>(nameof(ICredentialAuthentication)); var _dataContext = context.OwinContext.GetPerRequestValue <IDataContext>(nameof(IDataContext)); #region delete old logons if they exist Operation.Try(() => { var oldToken = context.Request.Headers.GetValues(WebConstants.OAuthCustomHeaders_OldToken)?.FirstOrDefault() ?? null; if (oldToken != null) { var logon = _cache.GetOrRefresh <UserLogon>(oldToken); if (logon != null) { logon.Invalidated = true; _dataContext.Store <UserLogon>().Modify(logon, true); _cache.Invalidate(oldToken); } } }) #endregion #region Verify the user exists .Then(opr => { return(_dataContext.Store <User>().Query .Where(_u => _u.EntityId == context.UserName) .FirstOrDefault() .ThrowIfNull("invalid user credential") .ThrowIf(_u => _u.Status != (int)AccountStatus.Active, "inactive user account")); }) #endregion #region verify credentials with the credential authority .Then(opr => { _credentialAuthority.VerifyCredential(new Credential { OwnerId = context.UserName, Metadata = CredentialMetadata.Password, Value = Encoding.UTF8.GetBytes(context.Password) }) .Resolve(); return(opr.Result); }) #endregion #region aggregate the claims that makeup the token .Then(opr => { var identity = new ClaimsIdentity(context.Options.AuthenticationType); //identity.AddClaim(new Claim("user-name", context.UserName)); identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); identity.AddClaim(new Claim(ClaimTypes.Sid, opr.Result.UId.ToString())); identity.AddClaim(new Claim("user-status", opr.Result.Status.ToString())); //roles _dataContext.Store <UserRole>().Query .Where(_ur => _ur.UserId == opr.Result.EntityId) .ForAll((_cnt, _next) => identity.AddClaim(new Claim(ClaimTypes.Role, _next.RoleName))); context.Validated(new Microsoft.Owin.Security.AuthenticationTicket(identity, null)); }) #endregion #region if any of the above failed... .Error(opr => { context.SetError("invalid_grant", opr.Message); context.Rejected(); }); #endregion });