/// <summary>
 /// Security challenge child handler
 /// </summary>
 public SecurityPolicyChildHandler(IRepositoryService <SecurityDevice> deviceRepository, IRepositoryService <SecurityApplication> applicationRepository, IRepositoryService <SecurityRole> roleRepository, IPolicyEnforcementService pepService, IPolicyInformationService pipService)
 {
     this.m_pip                   = pipService;
     this.m_pep                   = pepService;
     this.m_roleRepository        = roleRepository;
     this.m_deviceRepository      = deviceRepository;
     this.m_applicationRepository = applicationRepository;
 }
Example #2
0
        /// <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));
        }
Example #3
0
        /// <summary>
        /// Authenticate the device
        /// </summary>
        public IPrincipal Authenticate(string deviceId, string deviceSecret, AuthenticationMethod authMethod = AuthenticationMethod.Any)
        {
            var config = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            if (!authMethod.HasFlag(AuthenticationMethod.Local))
            {
                throw new InvalidOperationException("Identity provider only supports local auth");
            }

            // Pre-event
            AuthenticatingEventArgs e = new AuthenticatingEventArgs(deviceId)
            {
            };

            this.Authenticating?.Invoke(this, e);
            if (e.Cancel)
            {
                this.m_tracer.TraceWarning("Pre-Event hook indicates cancel {0}", deviceId);
                return(e.Principal);
            }

            IPrincipal retVal = null;

            try
            {
                // Connect to the db
                var connection = this.CreateConnection();
                using (connection.Lock())
                {
                    // Password service
                    IPasswordHashingService passwordHash = ApplicationContext.Current.GetService(typeof(IPasswordHashingService)) as IPasswordHashingService;

                    DbSecurityDevice dbd = connection.Table <DbSecurityDevice>().FirstOrDefault(o => o.PublicId.ToLower() == deviceId.ToLower());
                    if (dbd == null)
                    {
                        throw new SecurityException(Strings.locale_authenticationFailure);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbd.Lockout.HasValue && dbd.Lockout > DateTime.Now)
                    {
                        throw new SecurityException(Strings.locale_accountLocked);
                    }
                    else if (dbd.ObsoletionTime != null)
                    {
                        throw new SecurityException(Strings.locale_accountObsolete);
                    }
                    else if (!String.IsNullOrEmpty(deviceSecret) && passwordHash.ComputeHash(deviceSecret) != dbd.DeviceSecret)
                    {
                        dbd.InvalidAuthAttempts++;
                        connection.Update(dbd);
                        throw new SecurityException(Strings.locale_authenticationFailure);
                    }
                    else if (config?.MaxInvalidLogins.HasValue == true && dbd.InvalidAuthAttempts > config?.MaxInvalidLogins)
                    { //s TODO: Make this configurable
                        dbd.Lockout = DateTime.Now.AddSeconds(30 * (dbd.InvalidAuthAttempts - config.MaxInvalidLogins.Value));
                        connection.Update(dbd);
                        throw new SecurityException(Strings.locale_accountLocked);
                    } // TODO: Lacks login permission
                    else
                    {
                        dbd.LastAuthTime        = DateTime.Now;
                        dbd.InvalidAuthAttempts = 0;
                        connection.Update(dbd);

                        IPolicyDecisionService    pdp = ApplicationContext.Current.GetService <IPolicyDecisionService>();
                        IPolicyInformationService pip = ApplicationContext.Current.GetService <IPolicyInformationService>();
                        List <IClaim>             additionalClaims = new List <IClaim>();
                        additionalClaims.AddRange(pip.GetPolicies(dbd).Where(o => o.Rule == PolicyGrantType.Grant).Select(o => new SanteDBClaim(SanteDBClaimTypes.SanteDBGrantedPolicyClaim, o.Policy.Oid)));
                        additionalClaims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBDeviceIdentifierClaim, dbd.Key.ToString()));
                        additionalClaims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBApplicationIdentifierClaim, ApplicationContext.Current.Application.Key.ToString())); // Local application only for SQLite
                        // Create the principal
                        retVal = new SQLitePrincipal(new SQLiteDeviceIdentity(dbd.PublicId, true, DateTime.Now, DateTime.Now.Add(config?.MaxLocalSession ?? new TimeSpan(0, 15, 0)), additionalClaims), new string[] { });

                        ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>().Demand(PermissionPolicyIdentifiers.LoginAsService, retVal);
                    }
                }

                // Post-event
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(deviceId, retVal, true));
            }
            catch (Exception ex)
            {
                this.m_tracer.TraceError("Error establishing device session ({1}): {0}", ex, deviceSecret);
                this.Authenticated?.Invoke(e, new AuthenticatedEventArgs(deviceId, retVal, false));

                throw;
            }

            return(retVal);
        }
 /// <summary>
 /// Gets the granted policies from the specified claims principal
 /// </summary>
 public static IEnumerable <IPolicyInstance> GetGrantedPolicies(this IClaimsPrincipal me, IPolicyInformationService pip)
 {
     return(me.Claims.Where(o => o.Type == SanteDBClaimTypes.SanteDBGrantedPolicyClaim).Select(o => new ClaimsPolicyInstance(me, pip.GetPolicy(o.Value))));
 }