/// <summary> /// Process a principal /// </summary> /// <param name="principal"></param> private void ProcessPrincipal(IPrincipal principal) { this.UserName = principal.Identity.Name; this.IsAuthenticated = principal.Identity.IsAuthenticated; this.AuthenticationType = principal.Identity.AuthenticationType; this.Principal = principal; if (principal is ClaimsPrincipal) { this.Token = principal.ToString(); } // Expiry / etc if (principal is ClaimsPrincipal) { var cp = principal as ClaimsPrincipal; this.Issued = ((cp.FindFirst(ClaimTypes.AuthenticationInstant) ?? cp.FindFirst("nbf"))?.AsDateTime().ToLocalTime() ?? DateTime.Now); this.Expiry = ((cp.FindFirst(ClaimTypes.Expiration) ?? cp.FindFirst("exp"))?.AsDateTime().ToLocalTime() ?? DateTime.MaxValue); this.Roles = cp.Claims.Where(o => o.Type == ClaimsIdentity.DefaultRoleClaimType)?.Select(o => o.Value)?.ToList(); this.AuthenticationType = cp.FindFirst(ClaimTypes.AuthenticationMethod)?.Value; var subKey = Guid.Empty; if (cp.HasClaim(o => o.Type == ClaimTypes.Sid)) { Guid.TryParse(cp.FindFirst(ClaimTypes.Sid)?.Value, out subKey); } } else { IRoleProviderService rps = ApplicationContext.Current.GetService <IRoleProviderService>(); this.Roles = rps.GetAllRoles(this.UserName).ToList(); this.Issued = DateTime.Now; this.Expiry = DateTime.MaxValue; } }
/// <summary> /// Create a token response /// </summary> private Stream CreateTokenResponse(IPrincipal oizPrincipal, IPrincipal clientPrincipal, EndpointReference appliesTo, IEnumerable <Claim> additionalClaims) { this.m_traceSource.TraceInformation("Will create new ClaimsPrincipal based on existing principal"); IRoleProviderService roleProvider = ApplicationContext.Current.GetService <IRoleProviderService>(); IPolicyInformationService pip = ApplicationContext.Current.GetService <IPolicyInformationService>(); IIdentityRefreshProviderService idp = ApplicationContext.Current.GetService <IIdentityRefreshProviderService>(); // TODO: Add configuration for expiry DateTime issued = DateTime.Parse((oizPrincipal as ClaimsPrincipal)?.FindFirst(ClaimTypes.AuthenticationInstant)?.Value ?? DateTime.Now.ToString("o")), expires = DateTime.Now.Add(this.m_configuration.ValidityTime); // System claims List <Claim> claims = new List <Claim>( roleProvider.GetAllRoles(oizPrincipal.Identity.Name).Select(r => new Claim(ClaimsIdentity.DefaultRoleClaimType, r)) ) { new Claim("iss", this.m_configuration.IssuerName), new Claim(ClaimTypes.Name, oizPrincipal.Identity.Name) }; // Additional claims claims.AddRange(additionalClaims); // Get policies var oizPrincipalPolicies = pip.GetActivePolicies(oizPrincipal); // Add grant if not exists if ((oizPrincipal as ClaimsPrincipal)?.FindFirst(ClaimTypes.Actor)?.Value == UserClassKeys.HumanUser.ToString()) { claims.AddRange(new Claim[] { //new Claim(ClaimTypes.AuthenticationInstant, issued.ToString("o")), new Claim(ClaimTypes.AuthenticationMethod, "OAuth2"), new Claim(OpenIzClaimTypes.OpenIzApplicationIdentifierClaim, (clientPrincipal as ClaimsPrincipal).FindFirst(ClaimTypes.Sid).Value) }); if ((oizPrincipal as ClaimsPrincipal)?.HasClaim(o => o.Type == OpenIzClaimTypes.OpenIzGrantedPolicyClaim) == true) { claims.AddRange((oizPrincipal as ClaimsPrincipal).FindAll(OpenIzClaimTypes.OpenIzGrantedPolicyClaim)); } else { claims.AddRange(oizPrincipalPolicies.Where(o => o.Rule == PolicyDecisionOutcomeType.Grant).Select(o => new Claim(OpenIzClaimTypes.OpenIzGrantedPolicyClaim, o.Policy.Oid))); } // Is the user elevated? If so, add claims for those policies if (claims.Exists(o => o.Type == OpenIzClaimTypes.XspaPurposeOfUseClaim)) { claims.AddRange(oizPrincipalPolicies.Where(o => o.Rule == PolicyDecisionOutcomeType.Elevate).Select(o => new Claim(OpenIzClaimTypes.OpenIzGrantedPolicyClaim, o.Policy.Oid))); } // Add Email address from idp claims.AddRange((oizPrincipal as ClaimsPrincipal).Claims.Where(o => o.Type == ClaimTypes.Email)); var tel = (oizPrincipal as ClaimsPrincipal).Claims.FirstOrDefault(o => o.Type == ClaimTypes.MobilePhone)?.Value; if (!String.IsNullOrEmpty(tel)) { claims.Add(new Claim("tel", tel)); } } // Name identifier claims.AddRange((oizPrincipal as ClaimsPrincipal).Claims.Where(o => o.Type == ClaimTypes.NameIdentifier)); // Find the nameid var nameId = claims.Find(o => o.Type == ClaimTypes.NameIdentifier); if (nameId != null) { claims.Remove(nameId); claims.Add(new Claim("sub", nameId.Value)); } var principal = new ClaimsPrincipal(new ClaimsIdentity(oizPrincipal.Identity, claims)); SigningCredentials credentials = this.CreateSigningCredentials(); // Generate security token var jwt = new JwtSecurityToken( signingCredentials: credentials, audience: appliesTo.Uri.ToString(), notBefore: issued, expires: expires, claims: claims ); JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); var encoder = handler.SignatureProviderFactory.CreateForSigning(credentials.SigningKey, credentials.SignatureAlgorithm); var refreshGrant = idp.CreateRefreshToken(oizPrincipal, expires.AddMinutes(10)); var refreshToken = String.Format("{0}.{1}", BitConverter.ToString(encoder.Sign(refreshGrant)).Replace("-", ""), BitConverter.ToString(refreshGrant).Replace("-", "")); WebOperationContext.Current.OutgoingResponse.ContentType = "application/json"; OAuthTokenResponse response = new OAuthTokenResponse() { TokenType = OAuthConstants.JwtTokenType, AccessToken = handler.WriteToken(jwt), ExpiresIn = (int)(expires.Subtract(DateTime.Now)).TotalMilliseconds, RefreshToken = refreshToken // TODO: Need to write a SessionProvider for this so we can keep track of refresh tokens }; return(this.CreateResponse(response)); }
/// <summary> /// Process a principal /// </summary> /// <param name="principal"></param> private void ProcessPrincipal(IPrincipal principal) { this.UserName = principal.Identity.Name; this.IsAuthenticated = principal.Identity.IsAuthenticated; this.AuthenticationType = principal.Identity.AuthenticationType; this.Principal = principal; if (principal is ClaimsPrincipal) { this.Token = principal.ToString(); } // Expiry / etc if (principal is ClaimsPrincipal) { var cp = principal as ClaimsPrincipal; this.Issued = (cp.FindClaim(ClaimTypes.AuthenticationInstant)?.AsDateTime().ToLocalTime() ?? DateTime.Now); this.Expiry = (cp.FindClaim(ClaimTypes.Expiration)?.AsDateTime().ToLocalTime() ?? DateTime.MaxValue); this.Roles = cp.Claims.Where(o => o.Type == ClaimsIdentity.DefaultRoleClaimType)?.Select(o => o.Value)?.ToList(); this.AuthenticationType = cp.FindClaim(ClaimTypes.AuthenticationMethod)?.Value; var subKey = Guid.Empty; if (cp.HasClaim(o => o.Type == ClaimTypes.Sid)) { Guid.TryParse(cp.FindClaim(ClaimTypes.Sid)?.Value, out subKey); } } else if (principal is SQLitePrincipal) { var sqlPrincipal = principal as SQLitePrincipal; this.Issued = sqlPrincipal.IssueTime; this.Expiry = sqlPrincipal.Expires; IRoleProviderService rps = ApplicationContext.Current.GetService <IRoleProviderService>(); this.Roles = rps.GetAllRoles(this.UserName).ToList(); } else { IRoleProviderService rps = ApplicationContext.Current.GetService <IRoleProviderService>(); this.Roles = rps.GetAllRoles(this.UserName).ToList(); this.Issued = DateTime.Now; this.Expiry = DateTime.MaxValue; } // Grab the user entity String errDetail = String.Empty; // Try to get user entity try { var userService = ApplicationContext.Current.GetService <ISecurityRepositoryService>(); var securityUser = userService.GetUser(principal.Identity); if (securityUser == null) // Not yet persisted, get from server { this.SecurityUser = new SecurityUser() { Key = Guid.Parse((principal as ClaimsPrincipal).FindClaim(ClaimTypes.Sid).Value), UserName = principal.Identity.Name } } ; else { this.SecurityUser = securityUser; } // User entity available? this.m_entity = userService.GetUserEntity(principal.Identity); // Attempt to download if the user entity is null // Or if there are no relationships of type dedicated service dedicated service delivery location to force a download of the user entity var amiService = ApplicationContext.Current.GetService <IClinicalIntegrationService>(); if (amiService != null && amiService.IsAvailable() || this.m_entity == null || this.m_entity?.Relationships.All(r => r.RelationshipTypeKey != EntityRelationshipTypeKeys.DedicatedServiceDeliveryLocation) == true) { int t = 0; var sid = Guid.Parse((principal as ClaimsPrincipal)?.FindClaim(ClaimTypes.Sid)?.Value ?? ApplicationContext.Current.GetService <IDataPersistenceService <SecurityUser> >().QueryFast(o => o.UserName == principal.Identity.Name, 0, 1, out t, Guid.Empty).FirstOrDefault()?.Key.ToString()); this.m_entity = amiService.Find <UserEntity>(o => o.SecurityUser.Key == sid, 0, 1, null).Item?.OfType <UserEntity>().FirstOrDefault(); ApplicationContext.Current.GetService <IThreadPoolService>().QueueUserWorkItem(o => { var persistence = ApplicationContext.Current.GetService <IDataPersistenceService <UserEntity> >(); try { if (persistence.Get((o as Entity).Key.Value) == null) { persistence.Insert(o as Entity); } else { persistence.Update(o as Entity); } } catch (Exception e) { this.m_tracer.TraceError("Could not create / update user entity for logged in user: {0}", e); } }, this.m_entity); } } catch (Exception e) { this.m_tracer.TraceError("Error getting extended session information: {0}", e); errDetail = String.Format("dbErr={0}", e.Message); } // Only subscribed faciliites if (ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>().OnlySubscribedFacilities) { var subFacl = ApplicationContext.Current.Configuration.GetSection <SynchronizationConfigurationSection>().Facilities; var isInSubFacility = this.m_entity?.LoadCollection <EntityRelationship>("Relationships").Any(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.DedicatedServiceDeliveryLocation && subFacl.Contains(o.TargetEntityKey.ToString())) == true; if (!isInSubFacility && ApplicationContext.Current.PolicyDecisionService.GetPolicyOutcome(principal, PolicyIdentifiers.AccessClientAdministrativeFunction) != PolicyGrantType.Grant) { if (this.m_entity == null) { this.m_tracer.TraceError("User facility check could not be done : entity null"); errDetail += " entity_null"; } else { this.m_tracer.TraceError("User is in facility {0} but tablet only allows login from {1}", String.Join(",", this.m_entity?.LoadCollection <EntityRelationship>("Relationships").Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.DedicatedServiceDeliveryLocation).Select(o => o.TargetEntityKey).ToArray()), String.Join(",", subFacl) ); errDetail += String.Format(" entity={0}, facility={1}", String.Join(",", this.m_entity?.LoadCollection <EntityRelationship>("Relationships").Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.DedicatedServiceDeliveryLocation).Select(o => o.TargetEntityKey).ToArray()), String.Join(",", subFacl)); } throw new SecurityException(String.Format(Strings.locale_loginFromUnsubscribedFacility, errDetail)); } } }