コード例 #1
0
        /// <summary>
        /// Authetnicate
        /// </summary>
        private IDisposable Authenticate(Hl7MessageReceivedEventArgs e)
        {
            IPrincipal principal      = null;
            var        msh            = e.Message.GetStructure("MSH") as MSH;
            var        sft            = e.Message.GetStructure("SFT") as SFT;
            var        sessionService = ApplicationServiceContext.Current.GetService <ISessionProviderService>();

            if (string.IsNullOrEmpty(msh.Security.Value) && this.m_configuration.Security == Configuration.AuthenticationMethod.Msh8)
            {
                this.m_traceSource.TraceError("Must carry MSH-8 authorization token information");
                throw new SecurityException(this.m_localizationService.GetString("error.messaging.h17.authorizationToken"));
            }
            if (msh.Security.Value?.StartsWith("sid://") == true) // Session identifier
            {
                var session = sessionService.Get(Enumerable.Range(5, msh.Security.Value.Length - 5)
                                                 .Where(x => x % 2 == 0)
                                                 .Select(x => Convert.ToByte(msh.Security.Value.Substring(x, 2), 16))
                                                 .ToArray());
                principal = ApplicationServiceContext.Current.GetService <ISessionIdentityProviderService>().Authenticate(session) as IClaimsPrincipal;
            }
            else if (e is AuthenticatedHl7MessageReceivedEventArgs auth && auth.AuthorizationToken != null)
            {
                // Ensure proper authentication exists
                if (String.IsNullOrEmpty(msh.SendingApplication.NamespaceID.Value))
                {
                    this.m_traceSource.TraceError("MSH-3 must be provided for authenticating device/application");
                    throw new SecurityException(this.m_localizationService.FormatString("error.messaging.h17.authenticating", new
                    {
                        param  = "MSH-3",
                        param2 = " device/application"
                    }));
                }
                else if (this.m_configuration.Security == Configuration.AuthenticationMethod.Sft4 && string.IsNullOrEmpty(sft.SoftwareBinaryID.Value))
                {
                    this.m_traceSource.TraceError("SFT-4 must be provided for authenticating application");
                    throw new SecurityException(this.m_localizationService.FormatString("error.messaging.h17.authenticating", new
                    {
                        param  = "SFT-4",
                        param2 = " application"
                    }));
                }
                else if (this.m_configuration.Security == Configuration.AuthenticationMethod.Msh8 && string.IsNullOrEmpty(msh.Security.Value))
                {
                    this.m_traceSource.TraceError("MSH-8 must be provided for authenticating application");
                    throw new SecurityException(this.m_localizationService.FormatString("error.messaging.h17.authenticating", new
                    {
                        param  = "MSH-8",
                        param2 = " application"
                    }));
                }

                String applicationId = msh.SendingApplication.NamespaceID.Value, applicationSecret = null;

                switch (this.m_configuration.Security)
                {
                case Configuration.AuthenticationMethod.None:     // No special - authenticate the app using device creds
                    applicationSecret = this.m_configuration.NoAuthenticationSecret;
                    break;

                case Configuration.AuthenticationMethod.Msh8:
                    applicationSecret = msh.Security.Value;
                    break;

                case Configuration.AuthenticationMethod.Sft4:
                    applicationSecret = sft.SoftwareBinaryID.Value;
                    break;
                }

                IPrincipal certificatePrincipal = ApplicationServiceContext.Current.GetService <ICertificateIdentityProvider>()?.Authenticate(auth.AuthorizationToken);

                if (certificatePrincipal == null)
                {
                    throw new InvalidOperationException("In order to use node authentication with X509 certificates - there must be a CertificateIdentityProvider configured");
                }
                else if (certificatePrincipal.Identity is IApplicationIdentity)
                {
                    principal = certificatePrincipal;
                }
                else
                {
                    var applicationPrincipal = applicationSecret != null?ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>()?.Authenticate(applicationId, applicationSecret) : null;

                    if (applicationPrincipal == null && this.m_configuration.RequireAuthenticatedApplication)
                    {
                        this.m_traceSource.TraceError("Server requires authenticated application");
                        throw new UnauthorizedAccessException(this.m_localizationService.GetString("error.type.UnauthorizedAccessException"));
                    }
                    principal = new SanteDBClaimsPrincipal(new IIdentity[] { certificatePrincipal.Identity, applicationPrincipal?.Identity }.OfType <IClaimsIdentity>());
                }
            }
コード例 #2
0
        /// <summary>
        /// Apply the policy to the request
        /// </summary>
        public void Apply(RestRequestMessage request)
        {
            IDisposable context = null;

            try
            {
                this.m_traceSource.TraceInfo("Entering BasicAuthorizationAccessPolicy");

                // Role service
                var roleService     = ApplicationServiceContext.Current.GetService <IRoleProviderService>();
                var identityService = ApplicationServiceContext.Current.GetService <IIdentityProviderService>();
                var pipService      = ApplicationServiceContext.Current.GetService <IPolicyInformationService>();
                var pdpService      = ApplicationServiceContext.Current.GetService <IPolicyDecisionService>();

                var httpRequest = RestOperationContext.Current.IncomingRequest;

                var authHeader = httpRequest.Headers["Authorization"];
                if (String.IsNullOrEmpty(authHeader) ||
                    !authHeader.ToLowerInvariant().StartsWith("basic"))
                {
                    throw new AuthenticationException("Invalid authentication scheme");
                }
                authHeader = authHeader.Substring(6);
                var b64Data = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader)).Split(':');
                if (b64Data.Length != 2)
                {
                    throw new SecurityException("Malformed HTTP Basic Header");
                }

                var principal = identityService.Authenticate(b64Data[0], b64Data[1]);
                if (principal == null)
                {
                    throw new AuthenticationException("Invalid username/password");
                }

                // Add claims made by the client
                var claims = new List <IClaim>();
                if (principal is IClaimsPrincipal)
                {
                    claims.AddRange((principal as IClaimsPrincipal).Claims);
                }

                var clientClaims = SanteDBClaimsUtil.ExtractClaims(httpRequest.Headers);
                foreach (var claim in clientClaims)
                {
                    if (this.m_configuration?.AllowedClientClaims?.Contains(claim.Type) == false)
                    {
                        throw new SecurityException("Claim not allowed");
                    }
                    else
                    {
                        var handler = SanteDBClaimsUtil.GetHandler(claim.Type);
                        if (handler == null ||
                            handler.Validate(principal, claim.Value))
                        {
                            claims.Add(claim);
                        }
                        else
                        {
                            throw new SecurityException("Claim validation failed");
                        }
                    }
                }

                // Claim headers built in
                if (pipService != null)
                {
                    claims.AddRange(pdpService.GetEffectivePolicySet(principal).Where(o => o.Rule == PolicyGrantType.Grant).Select(o => new SanteDBClaim(SanteDBClaimTypes.SanteDBGrantedPolicyClaim, o.Policy.Oid)));
                }

                // Finally validate the client
                var claimsPrincipal = new SanteDBClaimsPrincipal(new SanteDBClaimsIdentity(principal.Identity, claims));

                if (this.m_configuration?.RequireClientAuth == true)
                {
                    var clientAuth = httpRequest.Headers[SanteDBRestConstants.BasicHttpClientCredentialHeaderName];
                    if (clientAuth == null ||
                        !clientAuth.StartsWith("basic", StringComparison.InvariantCultureIgnoreCase))
                    {
                        throw new SecurityException("Client credentials invalid");
                    }
                    else
                    {
                        String   clientAuthString     = clientAuth.Substring(clientAuth.IndexOf("basic", StringComparison.InvariantCultureIgnoreCase) + 5).Trim();
                        String[] authComps            = Encoding.UTF8.GetString(Convert.FromBase64String(clientAuthString)).Split(':');
                        var      applicationPrincipal = ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>().Authenticate(authComps[0], authComps[1]);
                        claimsPrincipal.AddIdentity(applicationPrincipal.Identity as IClaimsIdentity);
                    }
                }

                context = AuthenticationContext.EnterContext(principal);
            }
            catch (Exception e)
            {
                this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString());
            }
            finally
            {
                // Disposed context so reset the auth
                RestOperationContext.Current.Disposed += (o, e) => context?.Dispose();
            }
        }
コード例 #3
0
        /// <summary>
        /// Create an authorization context
        /// </summary>
        public IClaimsPrincipal CreateClaimsPrincipal(IEnumerable <IClaimsIdentity> otherIdentities = null)
        {
            if (!this.IsAuthenticated)
            {
                throw new SecurityException("Principal is not authenticated");
            }

            try
            {
                // System claims
                List <IClaim> claims = new List <IClaim>(

                    )
                {
                    new SanteDBClaim(SanteDBClaimTypes.AuthenticationMethod, this.m_authenticationType ?? "LOCAL"),
                    new SanteDBClaim(SanteDBClaimTypes.Sid, this.m_securityUser.Key.ToString()),
                    new SanteDBClaim(SanteDBClaimTypes.NameIdentifier, this.m_securityUser.Key.ToString()),
                    new SanteDBClaim(SanteDBClaimTypes.Actor, this.m_securityUser.UserClass.ToString()),
                };

                if (!this.Claims.Any(o => o.Type == SanteDBClaimTypes.Name))
                {
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.Name, this.m_securityUser.UserName));
                }
                if (!this.Claims.Any(o => o.Type == SanteDBClaimTypes.DefaultRoleClaimType))
                {
                    claims.AddRange(this.m_roles.Select(r => new SanteDBClaim(SanteDBClaimTypes.DefaultRoleClaimType, r.Name)));
                }
                if (this.m_securityUser.PasswordExpiration.HasValue && this.m_securityUser.PasswordExpiration < DateTime.Now)
                {
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.PurposeOfUse, PurposeOfUseKeys.SecurityAdmin.ToString()));
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBScopeClaim, PermissionPolicyIdentifiers.LoginPasswordOnly));
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBScopeClaim, PermissionPolicyIdentifiers.ReadMetadata));
                }
                if (this.m_securityUser.Email != null)
                {
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.Email, this.m_securityUser.Email));
                }
                if (this.m_securityUser.PhoneNumber != null)
                {
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.Telephone, this.m_securityUser.PhoneNumber));
                }


                this.AddClaims(claims);

                var identities = new IClaimsIdentity[] { this };
                if (otherIdentities != null)
                {
                    identities = identities.Union(otherIdentities).ToArray();
                }

                // TODO: Demographic data for the user
                var retVal = new SanteDBClaimsPrincipal(
                    identities
                    );
                s_traceSource.TraceInfo("Created security principal from identity {0} > {1}", this, AdoClaimsIdentity.PrincipalToString(retVal));
                return(retVal);
            }
            catch (Exception e)
            {
                s_traceSource.TraceEvent(EventLevel.Error, e.ToString());
                throw new Exception("Creating principal from identity failed", e);
            }
        }
コード例 #4
0
        /// <summary>
        /// Authetnicate
        /// </summary>
        private void Authenticate(Hl7MessageReceivedEventArgs e)
        {
            IPrincipal principal      = null;
            var        msh            = e.Message.GetStructure("MSH") as MSH;
            var        sft            = e.Message.GetStructure("SFT") as SFT;
            var        sessionService = ApplicationServiceContext.Current.GetService <ISessionProviderService>();

            if (String.IsNullOrEmpty(msh.Security.Value) && this.m_configuration.Security == SecurityMethod.Msh8)
            {
                throw new SecurityException("Must carry MSH-8 authorization token information");
            }
            if (msh.Security.Value?.StartsWith("sid://") == true) // Session identifier
            {
                var session = sessionService.Get(Enumerable.Range(5, msh.Security.Value.Length - 5)
                                                 .Where(x => x % 2 == 0)
                                                 .Select(x => Convert.ToByte(msh.Security.Value.Substring(x, 2), 16))
                                                 .ToArray());
                principal = ApplicationServiceContext.Current.GetService <ISessionIdentityProviderService>().Authenticate(session) as IClaimsPrincipal;
            }
            else if (e is AuthenticatedHl7MessageReceivedEventArgs)
            {
                var auth = e as AuthenticatedHl7MessageReceivedEventArgs;

                // Ensure proper authentication exists
                if (String.IsNullOrEmpty(msh.SendingFacility.NamespaceID.Value))
                {
                    throw new SecurityException("MSH-4 must be provided for authenticating device");
                }
                else if (String.IsNullOrEmpty(msh.SendingApplication.NamespaceID.Value))
                {
                    throw new SecurityException("MSH-3 must be provided for authenticating device/application");
                }
                else if (this.m_configuration.Security == SecurityMethod.Sft4 && String.IsNullOrEmpty(sft.SoftwareBinaryID.Value))
                {
                    throw new SecurityException("SFT-4 must be provided for authenticating application");
                }
                else if (this.m_configuration.Security == SecurityMethod.Msh8 && String.IsNullOrEmpty(msh.Security.Value))
                {
                    throw new SecurityException("MSH-8 must be provided for authenticating application");
                }

                String deviceId          = $"{msh.SendingApplication.NamespaceID.Value}|{msh.SendingFacility.NamespaceID.Value}",
                       deviceSecret      = BitConverter.ToString(auth.AuthorizationToken).Replace("-", ""),
                       applicationId     = msh.SendingApplication.NamespaceID.Value,
                       applicationSecret = this.m_configuration.Security == SecurityMethod.Sft4 ? sft.SoftwareBinaryID.Value : // Authenticate app by SFT4
                                           this.m_configuration.Security == SecurityMethod.Msh8 ? msh.Security.Value :         // Authenticate app by MSH-8
                                           BitConverter.ToString(auth.AuthorizationToken).Replace("-", "");                    // Authenticate app using X509 certificate on the device

                IPrincipal devicePrincipal      = ApplicationServiceContext.Current.GetService <IDeviceIdentityProviderService>().Authenticate(deviceId, deviceSecret, AuthenticationMethod.Local),
                           applicationPrincipal = applicationSecret != null?ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>()?.Authenticate(applicationId, applicationSecret) : null;

                if (applicationPrincipal == null && ApplicationServiceContext.Current.HostType == SanteDBHostType.Server)
                {
                    throw new UnauthorizedAccessException("Server requires authenticated application");
                }

                principal = new SanteDBClaimsPrincipal(new IIdentity[] { devicePrincipal.Identity, applicationPrincipal?.Identity }.OfType <IClaimsIdentity>());
            }
            else if (this.m_configuration.Security != SecurityMethod.None)
            {
                // Ensure proper authentication exists
                if (String.IsNullOrEmpty(msh.SendingFacility.NamespaceID.Value) || String.IsNullOrEmpty(msh.Security.Value))
                {
                    throw new SecurityException("MSH-4 and MSH-8 must always be provided for authenticating device when SLLP is not used");
                }
                else if (String.IsNullOrEmpty(msh.SendingFacility.NamespaceID.Value))
                {
                    throw new SecurityException("MSH-3 must be provided for authenticating application");
                }
                else if (this.m_configuration.Security == SecurityMethod.Sft4 && String.IsNullOrEmpty(sft.SoftwareBinaryID.Value))
                {
                    throw new SecurityException("SFT-4 must be provided for authenticating application");
                }
                else if (this.m_configuration.Security == SecurityMethod.Msh8 && String.IsNullOrEmpty(msh.Security.Value))
                {
                    throw new SecurityException("MSH-8 must be provided for authenticating application");
                }

                String deviceId          = $"{msh.SendingApplication.NamespaceID.Value}|{msh.SendingFacility.NamespaceID.Value}",
                       deviceSecret      = msh.Security.Value,
                       applicationId     = msh.SendingApplication.NamespaceID.Value,
                       applicationSecret = this.m_configuration.Security == SecurityMethod.Sft4 ? sft.SoftwareBinaryID.Value :
                                           this.m_configuration.Security == SecurityMethod.Msh8 ? msh.Security.Value : null;

                if (applicationSecret == deviceSecret && applicationSecret.Contains("+")) // Both device and app are using same auth key? Odd, perhaps there is the delimeter
                {
                    var secrets = applicationSecret.Split('+');
                    applicationSecret = secrets[1]; deviceSecret = secrets[0];
                }
                IPrincipal devicePrincipal      = ApplicationServiceContext.Current.GetService <IDeviceIdentityProviderService>().Authenticate(deviceId, deviceSecret, AuthenticationMethod.Local),
                           applicationPrincipal = applicationSecret != null?ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>()?.Authenticate(applicationId, applicationSecret) : null;

                if (applicationPrincipal == null && ApplicationServiceContext.Current.HostType == SanteDBHostType.Server)
                {
                    throw new UnauthorizedAccessException("Server requires authenticated application");
                }
                principal = new SanteDBClaimsPrincipal(new IIdentity[] { devicePrincipal.Identity, applicationPrincipal?.Identity }.OfType <IClaimsIdentity>());
            }
            else
            {
                switch (this.m_configuration.AnonymousUser?.ToUpper())
                {
                case "SYSTEM":
                    principal = AuthenticationContext.SystemPrincipal;
                    break;

                case "ANONYMOUS":
                default:
                    principal = AuthenticationContext.AnonymousPrincipal;
                    break;
                }
            }
            // Pricipal
            if (principal != null)
            {
                AuthenticationContext.Current = new AuthenticationContext(principal);
            }
        }