Пример #1
0
        /// <summary>
        /// Session token
        /// </summary>
        private IDisposable SetContextFromBearer(string bearerToken)
        {
            var bearerBinary = bearerToken.ParseHexString();
            var sessionId    = bearerBinary.Take(16).ToArray();
            var signature    = bearerBinary.Skip(16).ToArray();

            if (!ApplicationServiceContext.Current.GetService <IDataSigningService>().Verify(sessionId, signature))
            {
                throw new SecurityTokenException(SecurityTokenExceptionType.InvalidSignature, "Token has been tampered");
            }

            // Get the session
            var session = ApplicationServiceContext.Current.GetService <ISessionProviderService>().Get(
                sessionId
                );

            if (session == null)
            {
                return(AuthenticationContext.EnterContext(AuthenticationContext.AnonymousPrincipal));
            }

            IPrincipal principal = ApplicationServiceContext.Current.GetService <ISessionIdentityProviderService>().Authenticate(session);

            if (principal == null)
            {
                throw new SecurityTokenException(SecurityTokenExceptionType.KeyNotFound, "Invalid bearer token");
            }

            RestOperationContext.Current.Data.Add(SessionPropertyName, session);

            this.m_tracer.TraceVerbose("User {0} authenticated via SESSION BEARER", principal.Identity.Name);
            return(AuthenticationContext.EnterContext(principal));
        }
Пример #2
0
 /// <summary>
 /// Authenticate a user - this occurs when reauth is required
 /// </summary>
 /// <param name="context">Context.</param>
 public Credentials Authenticate(IRestClient context)
 {
     // TODO: Determine why we're reauthenticating... if it is an expired token we'll need to get the refresh token
     if (AuthenticationContext.Current.Principal is TokenClaimsPrincipal tokenCredentials)
     {
         var expiryTime = tokenCredentials.FindFirst(SanteDBClaimTypes.Expiration)?.AsDateTime();
         if (expiryTime.HasValue && expiryTime < DateTime.Now)
         {
             var idp       = ApplicationContext.Current.GetService <IIdentityProviderService>();
             var principal = idp.ReAuthenticate(AuthenticationContext.Current.Principal); // Force a re-issue
             AuthenticationContext.EnterContext(principal);                               // TODO: Figure out if this is still required
         }
         else if (expiryTime > DateTime.Now)                                              // Token is good?
         {
             return(this.GetCredentials(context));
         }
         else // I don't know what happened
         {
             throw new SecurityException("Server access token is expired");
         }
     }
     else
     {
         throw new SecurityException("Invalid authentication principal - Offline principal used to access server");
     }
     return(null);
 }
Пример #3
0
        /// <summary>
        /// Authenticate a user - this occurs when reauth is required
        /// </summary>
        /// <param name="context">Context.</param>
        public Credentials Authenticate(IRestClient context)
        {
            // TODO: Determine why we're reauthenticating... if it is an expired token we'll need to get the refresh token
            var tokenCredentials = AuthenticationContext.Current.Principal as TokenClaimsPrincipal;

            if (tokenCredentials != null)
            {
                var expiryTime = DateTime.MinValue;
                if (DateTime.TryParse(tokenCredentials.FindFirst(SanteDBClaimTypes.Expiration).Value, out expiryTime) &&
                    expiryTime < DateTime.Now)
                {
                    var idp       = ApplicationContext.Current.GetService(typeof(IIdentityProviderService)) as IIdentityProviderService;
                    var principal = idp.Authenticate(null, null);   // Force a re-issue
                    this.m_tokenCred = AuthenticationContext.EnterContext(principal);
                }
                else if (expiryTime > DateTime.Now) // Token is good?
                {
                    return(this.GetCredentials(context));
                }
                else // I don't know what happened
                {
                    throw new SecurityException();
                }
            }
            else
            {
                if (ApplicationContext.Current.Authenticate(new OAuthIdentityProvider(), context))
                {
                    return(this.GetCredentials(AuthenticationContext.Current.Principal));
                }
            }
            return(null);
        }
Пример #4
0
        /// <summary>
        /// Authenticates this system against the specified realm
        /// </summary>
        public static IPrincipal Authenticate(String realm, String user, String password)
        {
            var oauthRequest = new OAuthTokenRequest(user, password, "*")
            {
                ClientId     = "fiddler",
                ClientSecret = "fiddler"
            };

            // Client for authentication
            try
            {
                using (var client = CreateClient($"{realm}/auth", false))
                {
                    var response = client.Post <OAuthTokenRequest, OAuthTokenResponse>("oauth2_token", "application/x-www-form-urlencoded", oauthRequest);
                    if (!String.IsNullOrEmpty(response.AccessToken))
                    {
                        AuthenticationContext.EnterContext(new TokenClaimsPrincipal(response.AccessToken, response.IdToken, response.TokenType, response.RefreshToken, null));
                    }
                    else
                    {
                        throw new Exception("Could not retrieve token from server");
                    }
                    return(AuthenticationContext.Current.Principal);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Could not authenticate: {0}", e);
                throw new Exception($"Could not authenticate", e);
            }
        }
        /// <summary>
        /// Synchronize security locally
        /// </summary>
        private void SynchronizeSecurity(string deviceSecret, string deviceName, IPrincipal principal)
        {
            // Create a security user and ensure they exist!
            var localPip      = ApplicationContext.Current.GetService <IOfflinePolicyInformationService>();
            var localIdp      = ApplicationContext.Current.GetService <IOfflineDeviceIdentityProviderService>();
            var sdPersistence = ApplicationContext.Current.GetService <IDataPersistenceService <SecurityDevice> >();

            if (localIdp != null &&
                !String.IsNullOrEmpty(deviceSecret) && principal is IClaimsPrincipal &&
                ApplicationContext.Current.ConfigurationPersister.IsConfigured)
            {
                using (AuthenticationContext.EnterContext(principal))
                {
                    IClaimsPrincipal cprincipal = principal as IClaimsPrincipal;
                    var amiPip = new AmiPolicyInformationService();

                    IIdentity localDeviceIdentity = null;
                    lock (this.m_lockObject)
                    {
                        try
                        {
                            localDeviceIdentity = localIdp.GetIdentity(deviceName);
                            Guid sid = Guid.Parse(cprincipal.FindFirst(SanteDBClaimTypes.SanteDBDeviceIdentifierClaim).Value);
                            if (localDeviceIdentity == null)
                            {
                                localDeviceIdentity = localIdp.CreateIdentity(sid, deviceName, deviceSecret, AuthenticationContext.SystemPrincipal);
                            }
                            else
                            {
                                localIdp.ChangeSecret(deviceName, deviceSecret, AuthenticationContext.SystemPrincipal);
                            }
                        }
                        catch (Exception ex)
                        {
                            this.m_tracer.TraceWarning("Insertion of local cache credential failed: {0}", ex);
                        }

                        // Ensure policies exist from the claim
                        foreach (var itm in cprincipal.Claims.Where(o => o.Type == SanteDBClaimTypes.SanteDBGrantedPolicyClaim))
                        {
                            if (localPip.GetPolicy(itm.Value) == null)
                            {
                                try
                                {
                                    var policy = amiPip.GetPolicy(itm.Value);
                                    localPip.CreatePolicy(policy, AuthenticationContext.SystemPrincipal);
                                }
                                catch (Exception e)
                                {
                                    this.m_tracer.TraceWarning("Cannot update local policy information : {0}", e.Message);
                                }
                            }
                        }

                        localPip.AddPolicies(localDeviceIdentity, PolicyGrantType.Grant, AuthenticationContext.SystemPrincipal, cprincipal.Claims.Where(o => o.Type == SanteDBClaimTypes.SanteDBGrantedPolicyClaim).Select(o => o.Value).ToArray());
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Mimic an authentication
        /// </summary>
        internal static IDisposable AuthenticateFhir(string appId, byte[] appSecret)
        {
            var appIdService  = ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>();
            var appPrincipal  = appIdService.Authenticate(appId, BitConverter.ToString(appSecret).Replace("-", ""));
            var sesPvdService = ApplicationServiceContext.Current.GetService <ISessionProviderService>();
            var sesIdService  = ApplicationServiceContext.Current.GetService <ISessionIdentityProviderService>();
            var session       = sesPvdService.Establish(appPrincipal, "http://localhost", false, null, null, null);

            return(AuthenticationContext.EnterContext(sesIdService.Authenticate(session)));
        }
Пример #7
0
        /// <summary>
        /// Authenticate using the authentication provider
        /// </summary>
        internal bool Authenticate(IIdentityProviderService authenticationProvider, IRestClient context)
        {
            bool retVal = false;

            while (!retVal)
            {
                Console.WriteLine("Access denied, authentication required.");
                if (String.IsNullOrEmpty(this.m_configuration.User))
                {
                    Console.Write("Username:"******"Username:{0}", this.m_configuration.User);
                }

                if (String.IsNullOrEmpty(this.m_configuration.Password))
                {
                    this.m_configuration.Password = DisplayUtil.PasswordPrompt("Password:"******"Password:{0}", new String('*', this.m_configuration.Password.Length * 2));
                }

                // Now authenticate
                try
                {
                    var principal = (authenticationProvider as OAuthIdentityProvider)?.Authenticate(
                        new SanteDBClaimsPrincipal(new SanteDBClaimsIdentity(this.m_configuration.User, false, "OAUTH2")), this.m_configuration.Password) ??
                                    authenticationProvider.Authenticate(this.m_configuration.User, this.m_configuration.Password);
                    if (principal != null)
                    {
                        retVal           = true;
                        this.m_tokenAuth = AuthenticationContext.EnterContext(principal);
                    }
                    else
                    {
                        this.m_configuration.Password = null;
                    }
                }
                catch (Exception e)
                {
                    this.m_tracer.TraceError("Authentication error: {0}", e.Message);
                    this.m_configuration.Password = null;
                }
            }

            return(retVal);
        }
Пример #8
0
        /// <summary>
        /// Enter device context, throwing any exceptions
        /// </summary>
        public static IDisposable EnterDeviceContext()
        {
            var appConfig = ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>();

            // Expired or not exists
            if (!(s_devicePrincipal is IClaimsPrincipal cp) || (cp.FindFirst(SanteDBClaimTypes.Expiration)?.AsDateTime().ToLocalTime() ?? DateTime.MinValue) < DateTime.Now)
            {
                s_devicePrincipal = ApplicationContext.Current.GetService <IDeviceIdentityProviderService>().Authenticate(appConfig.DeviceName, appConfig.DeviceSecret);
            }
            return(AuthenticationContext.EnterContext(s_devicePrincipal));
        }
Пример #9
0
 /// <summary>
 /// Enter device context
 /// </summary>
 public static IDisposable TryEnterDeviceContext()
 {
     try
     {
         return(EnterDeviceContext());
     }
     catch (Exception e)
     {
         s_tracer.TraceWarning("Could not enter device context, falling back to existing context - {0}", e);
         return(AuthenticationContext.EnterContext(AuthenticationContext.Current.Principal));
     }
 }
        /// <summary>
        /// Apply the policy to the request
        /// </summary>
        public void Apply(RestRequestMessage request)
        {
            try
            {
                this.m_traceSource.TraceInfo("Entering OAuth BasicAuthorizationAccessPolicy");

                // Role service
                var identityService = ApplicationServiceContext.Current.GetService <IApplicationIdentityProviderService>();

                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 client credentials");
                }

                // Client secret
                RestOperationContext.Current.Data.Add("symm_secret", b64Data[1]);

                // If the current principal is set-up then add the identity if not then don't
                if (AuthenticationContext.Current.Principal == AuthenticationContext.AnonymousPrincipal)
                {
                    var contextToken = AuthenticationContext.EnterContext(principal);
                    RestOperationContext.Current.Disposed += (o, e) => contextToken.Dispose();
                }
                else
                {
                    (AuthenticationContext.Current.Principal as IClaimsPrincipal).AddIdentity(principal.Identity);
                }

                // Disposed context so reset the auth
            }
            catch (Exception e)
            {
                this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString());
            }
        }
Пример #11
0
 /// <summary>
 /// Gets or sets the credentials which are used to authenticate
 /// </summary>
 /// <returns>The credentials.</returns>
 /// <param name="context">Context.</param>
 public Credentials GetCredentials(IRestClient context)
 {
     if (!AuthenticationContext.Current.Principal.Identity.IsAuthenticated ||
         AuthenticationContext.Current.Principal == AuthenticationContext.AnonymousPrincipal)
     {
         var credentials = this.Authenticate(context);
         this.m_tokenCred = AuthenticationContext.EnterContext(credentials.Principal);
         return(credentials);
     }
     else
     {
         return(this.GetCredentials(AuthenticationContext.Current.Principal));
     }
 }
Пример #12
0
        /// <summary>
        /// Queries for a specified resource.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Returns the FHIR query result containing the results of the query.</returns>
        /// <exception cref="System.ArgumentNullException">parameters</exception>
        public virtual Bundle Query(System.Collections.Specialized.NameValueCollection parameters)
        {
            if (parameters == null)
            {
                this.m_traceSource.TraceError($"Argument {nameof(parameters)} null or empty");
                throw new ArgumentNullException(this.m_localizationService.GetString("error.type.ArgumentNullException"));
            }

            Core.Model.Query.NameValueCollection hdsiQuery = null;
            FhirQuery query = QueryRewriter.RewriteFhirQuery(typeof(TFhirResource), typeof(TModel), parameters, out hdsiQuery);

            // Do the query
            int totalResults = 0;
            var predicate    = QueryExpressionParser.BuildLinqExpression <TModel>(hdsiQuery);
            var hdsiResults  = this.Query(predicate, query.QueryId, query.Start, query.Quantity, out totalResults);

            var auth = AuthenticationContext.Current;

            // Return FHIR query result
            if (Environment.ProcessorCount > 4)
            {
                hdsiResults = hdsiResults.AsParallel().AsOrdered();
            }

            var retVal = new FhirQueryResult(typeof(TFhirResource).Name)
            {
                Results = hdsiResults.Select(o =>
                {
                    using (AuthenticationContext.EnterContext(auth.Principal))
                    {
                        return(new Bundle.EntryComponent()
                        {
                            Resource = this.MapToFhir(o),
                            Search = new Bundle.SearchComponent()
                            {
                                Mode = Bundle.SearchEntryMode.Match
                            }
                        });
                    }
                }).ToList(),
                Query        = query,
                TotalResults = totalResults
            };

            this.ProcessIncludes(hdsiResults, parameters, retVal);

            return(ExtensionUtil.ExecuteBeforeSendResponseBehavior(TypeRestfulInteraction.SearchType, this.ResourceType, MessageUtil.CreateBundle(retVal, Bundle.BundleType.Searchset)) as Bundle);
        }
        public void TestAdministrativeUserCreation()
        {
            // var dataPersistence = ApplicationServiceContext.Current.GetService<IDataPersistenceService<SecurityUser>>();
            var identityService = ApplicationServiceContext.Current.GetService <IIdentityProviderService>();
            var hashingService  = ApplicationServiceContext.Current.GetService <IPasswordHashingService>();

            using (AuthenticationContext.EnterContext(identityService.Authenticate("*****@*****.**", "password")))
            {
                var identity = identityService.CreateIdentity("*****@*****.**", "mypassword", AuthenticationContext.Current.Principal);
                Assert.IsNotNull(identity);
                Assert.IsFalse(identity.IsAuthenticated);
            }

            // Now verify with data persistence
            //var dataUser = dataPersistence.Query(u => u.UserName == "*****@*****.**", null).First();
            //Assert.AreEqual(hashingService.ComputeHash("mypassword"), dataUser.PasswordHash);
            //Assert.IsFalse(dataUser.Lockout.HasValue);
            //Assert.AreEqual(authContext.Identity.Name, dataUser.CreatedBy.UserName);
        }
        /// <summary>
        /// Checks bearer access token
        /// </summary>
        /// <returns>True if authorization is successful</returns>
        private IDisposable CheckBearerAccess(string authorizationToken)
        {
            var session = ApplicationServiceContext.Current.GetService <ISessionProviderService>().Get(
                Enumerable.Range(0, authorizationToken.Length)
                .Where(x => x % 2 == 0)
                .Select(x => Convert.ToByte(authorizationToken.Substring(x, 2), 16))
                .ToArray()
                );

            IPrincipal principal = ApplicationServiceContext.Current.GetService <ISessionIdentityProviderService>().Authenticate(session);

            if (principal == null)
            {
                throw new SecuritySessionException(SessionExceptionType.Other, "Invalid bearer token", null);
            }

            RestOperationContext.Current.Data.Add(RestPropertyNameSession, session);

            this.m_traceSource.TraceInfo("User {0} authenticated via SESSION BEARER", principal.Identity.Name);
            return(AuthenticationContext.EnterContext(principal));
        }
Пример #15
0
        /// <summary>
        /// Defines the entry point of the application.
        /// </summary>
        /// <param name="args">The arguments.</param>
        private static async Task Main(string[] args)
        {
            var parms = new ParameterParser <ConsoleParameters>().Parse(args);

            Console.WriteLine("SanteDB PatientImporter v{0} ({1})", Assembly.GetEntryAssembly().GetName().Version, Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion);
            Console.WriteLine("Copyright (C) 2015-2022 See NOTICE for contributors");

            AppDomain.CurrentDomain.UnhandledException += (o, e) =>
            {
                Console.WriteLine("Could not complete operation - {0}", e.ExceptionObject);
            };

            if (parms.Help || args.Length == 0)
            {
                new ParameterParser <ConsoleParameters>().WriteHelp(Console.Out);
            }
            else
            {
                // Authenticate
                using (AuthenticationContext.EnterContext(Authenticate(parms.Realm, parms.UserName, parms.Password))
                       )
                {
                    using (var client = CreateClient($"{parms.Realm}/hdsi", true))
                    {
                        // Authority key?
                        if (!string.IsNullOrEmpty(parms.EnterpriseIdDomain))
                        {
                            enterpriseDomain = client.Get <Bundle>("AssigningAuthority", new KeyValuePair <string, object>("domainName", parms.EnterpriseIdDomain)).Item.First().Key.Value;
                        }
                        if (!string.IsNullOrEmpty(parms.MrnDomain))
                        {
                            mrnDomain = client.Get <Bundle>("AssigningAuthority", new KeyValuePair <string, object>("domainName", parms.MrnDomain)).Item.First().Key.Value;
                        }
                        if (!string.IsNullOrEmpty(parms.SsnDomain))
                        {
                            ssnDomain = client.Get <Bundle>("AssigningAuthority", new KeyValuePair <string, object>("domainName", parms.SsnDomain)).Item.First().Key.Value;
                        }
                        if (!string.IsNullOrEmpty(parms.FebrlDomain))
                        {
                            febrlDomain = client.Get <Bundle>("AssigningAuthority", new KeyValuePair <string, object>("domainName", parms.FebrlDomain)).Item.First().Key.Value;
                        }
                    }
                }

                // Process files
                var files = parms.Source.OfType <String>().SelectMany(s =>
                {
                    if (s.Contains("*"))
                    {
                        return(Directory.GetFiles(Path.GetDirectoryName(s), Path.GetFileName(s)));
                    }
                    else
                    {
                        return new String[] { s }
                    };
                });

                switch (parms.DatasetName.ToLowerInvariant())
                {
                case "onc":
                    foreach (var f in files)
                    {
                        await SeedOncDatasetAsync(new { FileName = f, Parameters = parms });
                    }
                    break;

                case "febrl":
                    foreach (var f in files)
                    {
                        await SeedFebrlDatasetAsync(new { FileName = f, Parameters = parms });
                    }
                    break;
                }
            }
        }
        /// <summary>
        /// Establish the session
        /// </summary>
        public ISession Establish(IPrincipal principal, string aud, bool isOverride, string purpose, string[] policyDemands, string language)
        {
            using (AuthenticationContext.EnterContext(principal))
            {
                try
                {
                    // Setup claims
                    var cprincipal = principal as IClaimsPrincipal;
                    var claims     = cprincipal.Claims.ToList();

                    // Did the caller explicitly set policies?
                    var pdp = ApplicationServiceContext.Current.GetService <IPolicyDecisionService>();

                    // Is the principal only valid for pwd reset?
                    if (!isOverride && cprincipal.HasClaim(o => o.Type == SanteDBClaimTypes.SanteDBScopeClaim)) // Allow the createor to specify
                    {
                        ;
                    }
                    else if (policyDemands?.Length > 0)
                    {
                        if (isOverride)
                        {
                            claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBOverrideClaim, "true"));
                        }
                        if (!String.IsNullOrEmpty(purpose))
                        {
                            claims.Add(new SanteDBClaim(SanteDBClaimTypes.PurposeOfUse, purpose));
                        }

                        foreach (var pol in policyDemands)
                        {
                            // Get grant
                            var grant = pdp.GetPolicyOutcome(cprincipal, pol);
                            if (isOverride && grant == PolicyGrantType.Elevate &&
                                (pol.StartsWith(PermissionPolicyIdentifiers.SecurityElevations) || // Special security elevations don't require override permission
                                 pdp.GetPolicyOutcome(cprincipal, PermissionPolicyIdentifiers.OverridePolicyPermission) == PolicyGrantType.Grant
                                ))                                                                 // We are attempting to override
                            {
                                claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBScopeClaim, pol));
                            }
                            else if (grant == PolicyGrantType.Grant)
                            {
                                claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBScopeClaim, pol));
                            }
                            else
                            {
                                throw new PolicyViolationException(cprincipal, pol, grant);
                            }
                        }
                    }

                    var sessionKey     = Guid.NewGuid();
                    var sessionRefresh = Guid.NewGuid();
                    claims.Add(new SanteDBClaim(SanteDBClaimTypes.SanteDBSessionIdClaim, sessionKey.ToString()));

                    // Add default policy claims
                    if (pdp != null)
                    {
                        // Add default policies
                        var oizPrincipalPolicies = pdp.GetEffectivePolicySet(cprincipal);
                        // Scopes user is allowed to access
                        claims.AddRange(oizPrincipalPolicies.Where(o => o.Rule == PolicyGrantType.Grant).Select(o => new SanteDBClaim(SanteDBClaimTypes.SanteDBScopeClaim, o.Policy.Oid)));
                    }

                    if (!String.IsNullOrEmpty(language))
                    {
                        claims.Add(new SanteDBClaim(SanteDBClaimTypes.Language, language));
                    }

                    // Is the principal a remote principal (i.e. not issued by us?)
                    MemorySession memorySession = null;
                    if (principal is IOfflinePrincipal)
                    {
                        memorySession = new MemorySession(sessionKey, DateTime.Now, DateTime.Now.Add(this.m_securityConfig.MaxLocalSession), sessionRefresh.ToByteArray(), claims.ToArray(), principal);
                    }
                    else
                    {
                        DateTime notAfter  = claims.FirstOrDefault(o => o.Type == SanteDBClaimTypes.Expiration).AsDateTime(),
                                 notBefore = claims.FirstOrDefault(o => o.Type == SanteDBClaimTypes.AuthenticationInstant).AsDateTime();
                        memorySession = new MemorySession(sessionKey, notBefore, notAfter, sessionRefresh.ToByteArray(), claims.ToArray(), principal);
                    }

                    this.m_session.Add(this.GetSessionKey(sessionKey.ToByteArray()), memorySession, memorySession.NotAfter.AddMinutes(10));
                    this.Established?.Invoke(this, new SessionEstablishedEventArgs(principal, memorySession, true, isOverride, purpose, policyDemands));
                    return(memorySession);
                }
                catch (Exception e)
                {
                    this.Established?.Invoke(this, new SessionEstablishedEventArgs(principal, null, false, isOverride, purpose, policyDemands));
                    throw new Exception($"Error establishing session for {principal.Identity.Name}", e);
                }
            }
        }
        /// <summary>
        /// Authenticate OAUTH
        /// </summary>
        public OAuthTokenResponse AuthenticateOAuth(NameValueCollection request)
        {
            this.ThrowIfNotRunning();

            try
            {
                var sessionService  = ApplicationContext.Current.GetService <ISessionProviderService>();
                var identityService = ApplicationContext.Current.GetService <IIdentityProviderService>();
                var remoteEp        = RemoteEndpointUtil.Current.GetRemoteClient()?.RemoteAddress;

                var claimsHeader = RestOperationContext.Current.IncomingRequest.Headers[HeaderTypes.HttpClaims];
                IDictionary <String, String> headerClaims = null;
                if (!String.IsNullOrEmpty(claimsHeader))
                {
                    headerClaims = Encoding.UTF8.GetString(Convert.FromBase64String(claimsHeader)).Split(';').ToDictionary(o => o.Split('=')[0], o => o.Split('=')[1]);
                }

                ISession session = null;

                var scopes           = request["scope"] == "*" ? null : request["scope"]?.Split(' ');
                var isOverride       = scopes?.Any(o => o == PermissionPolicyIdentifiers.OverridePolicyPermission) == true || headerClaims != null && headerClaims.TryGetValue(SanteDBClaimTypes.SanteDBOverrideClaim, out string overrideFlag) && overrideFlag == "true";
                var purposeOfUse     = headerClaims?.FirstOrDefault(o => o.Key == SanteDBClaimTypes.PurposeOfUse).Value;
                var tfa              = RestOperationContext.Current.IncomingRequest.Headers[HeaderTypes.HttpTfaSecret];
                var signatureService = ApplicationServiceContext.Current.GetService <IDataSigningService>();

                // Grant types
                switch (request["grant_type"])
                {
                case "x_challenge":
                {
                    var principal = ApplicationServiceContext.Current.GetService <ISecurityChallengeIdentityService>().Authenticate(request["username"], Guid.Parse(request["challenge"]), request["response"], tfa);
                    if (principal != null)
                    {
                        session = sessionService.Establish(principal, remoteEp, isOverride, purposeOfUse, scopes, request["ui_locales"]);
                    }
                    else
                    {
                        throw new SecurityException("Could not authenticate principal");
                    }
                    break;
                }

                case "password":
                {
                    IPrincipal principal = null;
                    if (isOverride && identityService is IElevatableIdentityProviderService elevatedAuth)
                    {
                        principal = elevatedAuth.ElevatedAuthenticate(request["username"], request["password"], tfa, purposeOfUse, scopes);
                    }
                    else if (!String.IsNullOrEmpty(tfa))
                    {
                        principal = identityService.Authenticate(request["username"], request["password"], tfa);
                    }
                    else
                    {
                        principal = identityService.Authenticate(request["username"], request["password"]);
                    }

                    using (AuthenticationContext.EnterContext(principal))
                    {
                        var lanugageCode = request["ui_locales"] ?? CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;

                        try
                        {
                            // TODO: Authenticate the device
                            var userEntity = ApplicationServiceContext.Current.GetService <ISecurityRepositoryService>()?.GetUserEntity(principal.Identity);
                            if (userEntity != null)
                            {
                                lanugageCode = userEntity?.LanguageCommunication?.FirstOrDefault(o => o.IsPreferred)?.LanguageCode ?? lanugageCode;
                            }
                        }
                        catch (Exception e)
                        {
                            this.m_tracer.TraceWarning("Cannot set the language of session from user preferences - {0}", e);
                        }         // Minor problem

                        if (principal != null)
                        {
                            session = sessionService.Establish(principal, remoteEp, isOverride, purposeOfUse, scopes, lanugageCode);
                        }
                        else
                        {
                            throw new SecurityException("Could not authenticate principal");
                        }
                    }
                }
                break;

                case "refresh_token":
                {
                    byte[] refreshToken = null;
                    if (request["refresh_token"].Equals("cookie") && RestOperationContext.Current.Data.TryGetValue(AgsAuthorizationServiceBehavior.SessionPropertyName, out object sessionData) && sessionData is ISession session1)         // hack: Use the cookie to llok up the current session
                    {
                        refreshToken = session1.RefreshToken;
                    }
                    else
                    {
                        byte[] refreshTokenData = request["refresh_token"].ParseHexString(),
                        signature    = refreshTokenData.Skip(16).ToArray();
                        refreshToken = refreshTokenData.Take(16).ToArray();

                        if (!signatureService.Verify(refreshToken, signature))
                        {
                            throw new SecurityException("Refresh token signature mismatch");
                        }
                    }
                    // Get the local session
                    session = sessionService.Extend(refreshToken);
                    break;
                }

                case "pin":
                {
                    var        pinAuthSvc = ApplicationServiceContext.Current.GetService <IPinAuthenticationService>();
                    IPrincipal principal  = pinAuthSvc.Authenticate(request["username"], request["pin"].Select(o => Byte.Parse(o.ToString())).ToArray());
                    if (principal != null)
                    {
                        session = sessionService.Establish(principal, remoteEp, isOverride, purposeOfUse, scopes, request["ui_locales"]);
                    }
                    else
                    {
                        throw new SecurityException("Could not authenticate principal");
                    }
                    break;
                }

                case "client_credentials":     // Someone is asking to use the device credentials ... Make sure they can login on their current service
                {
                    var devAuthSvc = ApplicationContext.Current.GetService <IDeviceIdentityProviderService>();
                    var pep        = ApplicationServiceContext.Current.GetService <IPolicyEnforcementService>();

                    // Is the user allowed to use just the device credential?
                    if (scopes?.All(o => o == PermissionPolicyIdentifiers.LoginPasswordOnly) == true)
                    {
                        scopes = new string[]
                        {
                            PermissionPolicyIdentifiers.ReadMetadata
                        }
                    }
                    ;
                    else
                    {
                        pep.Demand(PermissionPolicyIdentifiers.LoginImpersonateApplication);
                    }

                    var appConfig    = ApplicationServiceContext.Current.GetService <IConfigurationManager>().GetSection <SecurityConfigurationSection>();
                    var rmtPrincipal = devAuthSvc.Authenticate(appConfig.DeviceName, appConfig.DeviceSecret);
                    scopes  = scopes ?? new String[] { "*" };
                    session = sessionService.Establish(rmtPrincipal, remoteEp, false, null, scopes.Union(new String[] { PermissionPolicyIdentifiers.LoginImpersonateApplication }).ToArray(), request["ui_locales"]);
                    break;
                }
                }

                var retVal = new OAuthTokenResponse()
                {
                    // TODO: Sign the access token
                    AccessToken  = $"{session.Id.ToHexString()}{signatureService.SignData(session.Id).ToHexString()}",
                    RefreshToken = $"{session.RefreshToken.ToHexString()}{signatureService.SignData(session.RefreshToken).ToHexString()}",
                    ExpiresIn    = (int)session.NotAfter.DateTime.Subtract(DateTime.Now).TotalSeconds,
                    TokenType    = "bearer",
                    IdToken      = this.HydrateToken(session)
                };

                // Set cookie for authentication
                RestOperationContext.Current.OutgoingResponse.SetCookie(new Cookie("_s", retVal.AccessToken, "/")
                {
                    HttpOnly = true,
                    Expires  = session.NotAfter.DateTime.ToUniversalTime(),
                    Expired  = false
                });
                return(retVal);
            }
            catch (Exception e)
            {
                this.m_tracer.TraceError("Error establishing session for {0}: {1}", request["username"], e);
                RestOperationContext.Current.OutgoingResponse.StatusCode = 400;
                var ie = e.InnerException;
                while (ie != null) // get the root cause
                {                  // Was the original exception thrown a remote OAUTH response?
                    if (ie is RestClientException <OAuthTokenResponse> oauth)
                    {
                        return(oauth.Result);
                    }
                    ie = ie.InnerException;
                }
                return(new OAuthTokenResponse()
                {
                    Error = "invalid_grant",
                    ErrorDescription = e.Message
                });
            }
        }
Пример #18
0
 public void Authenticate()
 {
     AuthenticationContext.EnterContext(AuthenticationContext.SystemPrincipal);
 }
Пример #19
0
 /// <summary>
 /// Sets the root path
 /// </summary>
 public InteractiveBase()
 {
     AuthenticationContext.EnterContext(AuthenticationContext.AnonymousPrincipal);
 }
Пример #20
0
        /// <summary>
        /// Requests the issuance of a BMS1 inventory report request
        /// </summary>
        public LogisticsInventoryReportMessageType IssueInventoryReportRequest(LogisticsInventoryReportRequestMessageType parameters)
        {
            // Status
            LogisticsInventoryReportMessageType retVal = new LogisticsInventoryReportMessageType()
            {
                StandardBusinessDocumentHeader = this.m_gs1Util.CreateDocumentHeader("logisticsInventoryReport", null)
            };


            // Date / time of report

            DateTime?reportFrom = parameters.logisticsInventoryReportRequest.First().reportingPeriod?.beginDate ?? DateTime.MinValue,
                    reportTo    = parameters.logisticsInventoryReportRequest.First().reportingPeriod?.endDate ?? DateTime.Now;

            // return value
            LogisticsInventoryReportType report = new LogisticsInventoryReportType()
            {
                creationDateTime   = DateTime.Now,
                documentStatusCode = DocumentStatusEnumerationType.ORIGINAL,
                documentActionCode = DocumentActionEnumerationType.CHANGE_BY_REFRESH,
                logisticsInventoryReportIdentification = new Ecom_EntityIdentificationType()
                {
                    entityIdentification = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0).ToString("X")
                },
                structureTypeCode = new StructureTypeCodeType()
                {
                    Value = "LOCATION_BY_ITEM"
                },
                documentActionCodeSpecified = true
            };

            var locationStockStatuses = new List <LogisticsInventoryReportInventoryLocationType>();

            // Next, we want to know which facilities for which we're getting the inventory report
            List <Place> filterPlaces = null;

            if (parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation != null &&
                parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation.Length > 0)
            {
                foreach (var filter in parameters.logisticsInventoryReportRequest.First().logisticsInventoryRequestLocation)
                {
                    int tc    = 0;
                    var id    = filter.inventoryLocation.gln ?? filter.inventoryLocation.additionalPartyIdentification?.FirstOrDefault()?.Value;
                    var place = this.m_placeRepository.Find(o => o.Identifiers.Any(i => i.Value == id), 0, 1, out tc).FirstOrDefault();
                    if (place == null)
                    {
                        Guid uuid = Guid.Empty;
                        if (Guid.TryParse(id, out uuid))
                        {
                            place = this.m_placeRepository.Get(uuid, Guid.Empty);
                        }

                        if (place == null)
                        {
                            this.m_tracer.TraceError($"Place {filter.inventoryLocation.gln} not found");
                            throw new FileNotFoundException(this.m_localizationService.FormatString("error.messaging.gs1.placeNotFound",
                                                                                                    new
                            {
                                param = filter.inventoryLocation.gln
                            }));
                        }
                    }
                    if (filterPlaces == null)
                    {
                        filterPlaces = new List <Place>()
                        {
                            place
                        }
                    }
                    ;
                    else
                    {
                        filterPlaces.Add(place);
                    }
                }
            }
            else
            {
                filterPlaces = this.m_placeRepository.Find(o => o.ClassConceptKey == EntityClassKeys.ServiceDeliveryLocation).ToList();
            }

            // Get the GLN AA data
            var oidService = ApplicationServiceContext.Current.GetService <IAssigningAuthorityRepositoryService>();
            var gln        = oidService.Get("GLN");
            var gtin       = oidService.Get("GTIN");

            if (gln == null || gln.Oid == null)
            {
                this.m_tracer.TraceError("GLN configuration must carry OID and be named GLN in repository");
                throw new InvalidOperationException(this.m_localizationService.FormatString("error.messaging.gs1.configuration", new
                {
                    param = "GLN",
                }));
            }
            if (gtin == null || gtin.Oid == null)
            {
                this.m_tracer.TraceError("GTIN configuration must carry OID and be named GTIN in repository");
                throw new InvalidOperationException(this.m_localizationService.FormatString("error.messaging.gs1.configuration", new
                {
                    param = "GTIN"
                }));
            }

            var masterAuthContext = AuthenticationContext.Current.Principal;

            // Create the inventory report
            filterPlaces.ToList().ForEach(place =>
            {
                using (AuthenticationContext.EnterContext(masterAuthContext))
                {
                    try
                    {
                        var locationStockStatus = new LogisticsInventoryReportInventoryLocationType();
                        lock (locationStockStatuses)
                            locationStockStatuses.Add(locationStockStatus);

                        // TODO: Store the GLN configuration domain name
                        locationStockStatus.inventoryLocation = this.m_gs1Util.CreateLocation(place);

                        var tradeItemStatuses = new List <TradeItemInventoryStatusType>();

                        // What are the relationships of held entities
                        var persistenceService = ApplicationServiceContext.Current.GetService <IDataPersistenceService <EntityRelationship> >();
                        var relationships      = persistenceService.Query(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.OwnedEntity && o.SourceEntityKey == place.Key.Value, AuthenticationContext.Current.Principal);
                        relationships.ToList().ForEach(rel =>
                        {
                            using (AuthenticationContext.EnterContext(masterAuthContext))
                            {
                                if (!(rel.TargetEntity is ManufacturedMaterial))
                                {
                                    var matl = this.m_manufMaterialRepository.Get(rel.TargetEntityKey.Value, Guid.Empty);
                                    if (matl == null)
                                    {
                                        Trace.TraceWarning("It looks like {0} owns {1} but {1} is not a mmat!?!?!", place.Key, rel.TargetEntityKey);
                                        return;
                                    }
                                    else
                                    {
                                        rel.TargetEntity = matl;
                                    }
                                }
                                var mmat = rel.TargetEntity as ManufacturedMaterial;
                                if (!(mmat is ManufacturedMaterial))
                                {
                                    return;
                                }

                                var mat          = this.m_materialRepository.Find(o => o.Relationships.Where(r => r.RelationshipType.Mnemonic == "Instance").Any(r => r.TargetEntity.Key == mmat.Key)).FirstOrDefault();
                                var instanceData = mat.LoadCollection <EntityRelationship>("Relationships").FirstOrDefault(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Instance);

                                decimal balanceOH = rel.Quantity ?? 0;

                                // get the adjustments the adjustment acts are allocations and transfers
                                var adjustments = this.m_stockService.FindAdjustments(mmat.Key.Value, place.Key.Value, reportFrom, reportTo);

                                // We want to roll back to the start time and re-calc balance oh at time?
                                if (reportTo.Value.Date < DateTime.Now.Date)
                                {
                                    var consumed = this.m_stockService.GetConsumed(mmat.Key.Value, place.Key.Value, reportTo, DateTime.Now);
                                    balanceOH   -= (decimal)consumed.Sum(o => o.Quantity ?? 0);

                                    if (balanceOH == 0 && this.m_stockService.GetConsumed(mmat.Key.Value, place.Key.Value, reportFrom, reportTo).Count() == 0)
                                    {
                                        return;
                                    }
                                }

                                ReferenceTerm cvx = null;
                                if (mat.TypeConceptKey.HasValue)
                                {
                                    cvx = ApplicationServiceContext.Current.GetService <IConceptRepositoryService>().GetConceptReferenceTerm(mat.TypeConceptKey.Value, "CVX");
                                }

                                var typeItemCode = new ItemTypeCodeType()
                                {
                                    Value           = cvx?.Mnemonic ?? mmat.TypeConcept?.Mnemonic ?? mat.Key.Value.ToString(),
                                    codeListVersion = cvx?.LoadProperty <CodeSystem>("CodeSystem")?.Authority ?? "SanteDB-MaterialType"
                                };

                                // First we need the GTIN for on-hand balance
                                lock (tradeItemStatuses)
                                    tradeItemStatuses.Add(new TradeItemInventoryStatusType()
                                    {
                                        gtin         = mmat.Identifiers.FirstOrDefault(o => o.Authority.DomainName == "GTIN")?.Value,
                                        itemTypeCode = typeItemCode,
                                        additionalTradeItemIdentification = mmat.Identifiers.Where(o => o.Authority.DomainName != "GTIN").Select(o => new AdditionalTradeItemIdentificationType()
                                        {
                                            additionalTradeItemIdentificationTypeCode = o.Authority.DomainName,
                                            Value = o.Value
                                        }).ToArray(),
                                        tradeItemDescription = mmat.Names.Select(o => new Description200Type()
                                        {
                                            Value = o.Component.FirstOrDefault()?.Value
                                        }).FirstOrDefault(),
                                        tradeItemClassification = new TradeItemClassificationType()
                                        {
                                            additionalTradeItemClassificationCode = mat.Identifiers.Where(o => o.Authority.Oid != gtin.Oid).Select(o => new AdditionalTradeItemClassificationCodeType()
                                            {
                                                codeListVersion = o.Authority.DomainName,
                                                Value           = o.Value
                                            }).ToArray()
                                        },
                                        inventoryDateTime        = DateTime.Now,
                                        inventoryDispositionCode = new InventoryDispositionCodeType()
                                        {
                                            Value = "ON_HAND"
                                        },
                                        transactionalItemData = new TransactionalItemDataType[]
                                        {
                                            new TransactionalItemDataType()
                                            {
                                                tradeItemQuantity = new QuantityType()
                                                {
                                                    measurementUnitCode = (mmat.QuantityConcept ?? mat?.QuantityConcept)?.ReferenceTerms.Select(o => new AdditionalLogisticUnitIdentificationType()
                                                    {
                                                        additionalLogisticUnitIdentificationTypeCode = o.ReferenceTerm.CodeSystem.Name,
                                                        Value = o.ReferenceTerm.Mnemonic
                                                    }).FirstOrDefault()?.Value,
                                                    Value = balanceOH
                                                },
                                                batchNumber                 = mmat.LotNumber,
                                                itemExpirationDate          = mmat.ExpiryDate.Value,
                                                itemExpirationDateSpecified = true
                                            }
                                        }
                                    });


                                foreach (var adjgrp in adjustments.GroupBy(o => o.ReasonConceptKey))
                                {
                                    var reasonConcept = ApplicationServiceContext.Current.GetService <IConceptRepositoryService>().GetConceptReferenceTerm(adjgrp.Key.Value, "GS1_STOCK_STATUS")?.Mnemonic;
                                    if (reasonConcept == null)
                                    {
                                        reasonConcept = (ApplicationServiceContext.Current.GetService <IConceptRepositoryService>().Get(adjgrp.Key.Value, Guid.Empty) as Concept)?.Mnemonic;
                                    }

                                    // Broken vials?
                                    lock (tradeItemStatuses)
                                        tradeItemStatuses.Add(new TradeItemInventoryStatusType()
                                        {
                                            gtin         = mmat.Identifiers.FirstOrDefault(o => o.Authority.DomainName == "GTIN")?.Value,
                                            itemTypeCode = typeItemCode,
                                            additionalTradeItemIdentification = mmat.Identifiers.Where(o => o.Authority.DomainName != "GTIN").Select(o => new AdditionalTradeItemIdentificationType()
                                            {
                                                additionalTradeItemIdentificationTypeCode = o.Authority.DomainName,
                                                Value = o.Value
                                            }).ToArray(),
                                            tradeItemClassification = new TradeItemClassificationType()
                                            {
                                                additionalTradeItemClassificationCode = mat.Identifiers.Where(o => o.Authority.Oid != gtin.Oid).Select(o => new AdditionalTradeItemClassificationCodeType()
                                                {
                                                    codeListVersion = o.Authority.DomainName,
                                                    Value           = o.Value
                                                }).ToArray()
                                            },
                                            tradeItemDescription = mmat.Names.Select(o => new Description200Type()
                                            {
                                                Value = o.Component.FirstOrDefault()?.Value
                                            }).FirstOrDefault(),
                                            inventoryDateTime        = DateTime.Now,
                                            inventoryDispositionCode = new InventoryDispositionCodeType()
                                            {
                                                Value = reasonConcept
                                            },
                                            transactionalItemData = new TransactionalItemDataType[]
                                            {
                                                new TransactionalItemDataType()
                                                {
                                                    transactionalItemLogisticUnitInformation = instanceData == null ? null : new TransactionalItemLogisticUnitInformationType()
                                                    {
                                                        numberOfLayers        = "1",
                                                        numberOfUnitsPerLayer = instanceData.Quantity.ToString(),
                                                        packageTypeCode       = new PackageTypeCodeType()
                                                        {
                                                            Value = mat.LoadCollection <EntityExtension>("Extensions").FirstOrDefault(o => o.ExtensionTypeKey == Gs1ModelExtensions.PackagingUnit)?.ExtensionValue?.ToString() ?? "CONT"
                                                        }
                                                    },
                                                    tradeItemQuantity = new QuantityType()
                                                    {
                                                        measurementUnitCode = (mmat.QuantityConcept ?? mat?.QuantityConcept)?.ReferenceTerms.Select(o => new AdditionalLogisticUnitIdentificationType()
                                                        {
                                                            additionalLogisticUnitIdentificationTypeCode = o.ReferenceTerm.CodeSystem.Name,
                                                            Value = o.ReferenceTerm.Mnemonic
                                                        }).FirstOrDefault()?.Value,
                                                        Value = Math.Abs(adjgrp.Sum(o => o.Participations.First(p => p.ParticipationRoleKey == ActParticipationKey.Consumable && p.PlayerEntityKey == mmat.Key).Quantity.Value))
                                                    },
                                                    batchNumber                 = mmat.LotNumber,
                                                    itemExpirationDate          = mmat.ExpiryDate.Value,
                                                    itemExpirationDateSpecified = true
                                                }
                                            }
                                        });
                                }
                            }
                        });

                        // Reduce
                        locationStockStatus.tradeItemInventoryStatus = tradeItemStatuses.ToArray();
                    }
                    catch (Exception e)
                    {
                        traceSource.TraceError("Error fetching stock data : {0}", e);
                    }
                }
                // TODO: Reduce and Group by GTIN
            });

            report.logisticsInventoryReportInventoryLocation = locationStockStatuses.ToArray();
            retVal.logisticsInventoryReport = new LogisticsInventoryReportType[] { report };
            return(retVal);
        }
Пример #21
0
        /// <summary>
        /// Apply the specified policy
        /// </summary>
        public void Apply(RestRequestMessage request)
        {
            IDisposable contextAuth = null;

            // Authorization header
            if (request.Headers["Authorization"] != null)
            {
                var authHeader = request.Headers["Authorization"].Split(' ');
                switch (authHeader[0].ToLowerInvariant()) // Type / scheme
                {
                case "basic":
                {
                    var idp        = ApplicationContext.Current.GetService <IIdentityProviderService>();
                    var authString = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader[1])).Split(':');
                    var principal  = idp.Authenticate(authString[0], authString[1]);
                    if (principal == null)
                    {
                        throw new UnauthorizedAccessException();
                    }
                    else
                    {
                        contextAuth = AuthenticationContext.EnterContext(principal);
                    }
                    this.m_tracer.TraceVerbose("Performed BASIC auth for {0}", AuthenticationContext.Current.Principal.Identity.Name);

                    break;
                }

                case "bearer":
                {
                    contextAuth = this.SetContextFromBearer(authHeader[1]);
                    break;
                }
                }
            }
            else if (request.Url.Query.Contains("_sessionId="))
            {
                var query   = NameValueCollection.ParseQueryString(request.Url.Query);
                var session = query["_sessionId"][0];
                contextAuth = this.SetContextFromBearer(session);
            }
            else if (request.Cookies["_s"] != null) // cookie authentication
            {
                try
                {
                    var token = request.Cookies["_s"].Value;
                    contextAuth = this.SetContextFromBearer(token);
                }
                catch (SanteDB.DisconnectedClient.Exceptions.SecurityTokenException)
                {
                    RestOperationContext.Current.OutgoingResponse.SetCookie(new Cookie("_s", "")
                    {
                        Discard = true,
                        Expired = true,
                        Expires = DateTime.Now
                    });
                    throw;
                }
            }

            // Dispose the context when the rest operation is disposed
            if (contextAuth != null)
            {
                RestOperationContext.Current.Disposed += (o, e) => contextAuth.Dispose();
            }
        }
        /// <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();
            }
        }
Пример #23
0
        /// <summary>
        /// Synchronize the security settings
        /// </summary>
        /// <param name="password"></param>
        /// <param name="principal"></param>
        private void SynchronizeSecurity(string password, IPrincipal principal)
        {
            // Create a security user and ensure they exist!
            var localRp  = ApplicationContext.Current.GetService <IOfflineRoleProviderService>();
            var localPip = ApplicationContext.Current.GetService <IOfflinePolicyInformationService>();
            var localIdp = ApplicationContext.Current.GetService <IOfflineIdentityProviderService>();

            if (localRp == null || localPip == null || localIdp == null)
            {
                return;
            }

            if (!String.IsNullOrEmpty(password) && principal is IClaimsPrincipal &&
                ApplicationContext.Current.ConfigurationPersister.IsConfigured)
            {
                using (AuthenticationContext.EnterContext(principal))
                {
                    IClaimsPrincipal cprincipal = principal as IClaimsPrincipal;
                    var amiPip = new AmiPolicyInformationService();

                    // We want to impersonate SYSTEM
                    //AndroidApplicationContext.Current.SetPrincipal(cprincipal);

                    // Ensure policies exist from the claim
                    foreach (var itm in cprincipal.Claims.Where(o => o.Type == SanteDBClaimTypes.SanteDBGrantedPolicyClaim).ToArray())
                    {
                        if (localPip.GetPolicy(itm.Value) == null)
                        {
                            try
                            {
                                var policy = amiPip.GetPolicy(itm.Value);
                                localPip.CreatePolicy(policy, AuthenticationContext.SystemPrincipal);
                            }
                            catch (Exception e)
                            {
                                this.m_tracer.TraceWarning("Cannot update local policy information : {0}", e.Message);
                            }
                        }
                    }

                    // Ensure roles exist from the claim
                    var localRoles = localRp.GetAllRoles();
                    foreach (var itm in cprincipal.Claims.Where(o => o.Type == SanteDBClaimTypes.DefaultRoleClaimType).ToArray())
                    {
                        // Ensure policy exists
                        try
                        {
                            var amiPolicies = amiPip.GetPolicies(new SecurityRole()
                            {
                                Name = itm.Value
                            }).ToArray();
                            foreach (var pol in amiPolicies)
                            {
                                if (localPip.GetPolicy(pol.Policy.Oid) == null)
                                {
                                    var policy = amiPip.GetPolicy(pol.Policy.Oid);
                                    localPip.CreatePolicy(policy, AuthenticationContext.SystemPrincipal);
                                }
                            }

                            // Local role doesn't exist
                            if (!localRoles.Contains(itm.Value))
                            {
                                localRp.CreateRole(itm.Value, AuthenticationContext.SystemPrincipal);
                            }
                            localRp.AddPoliciesToRoles(amiPolicies, new String[] { itm.Value }, AuthenticationContext.SystemPrincipal);
                        }
                        catch (Exception e)
                        {
                            this.m_tracer.TraceWarning("Could not fetch / refresh policies: {0}", e.Message);
                        }
                    }

                    var localUser = ApplicationContext.Current.ConfigurationPersister.IsConfigured ? localIdp.GetIdentity(principal.Identity.Name) : null;

                    try
                    {
                        Guid sid = Guid.Parse(cprincipal.FindFirst(SanteDBClaimTypes.Sid).Value);
                        if (localUser == null)
                        {
                            localIdp.CreateIdentity(sid, principal.Identity.Name, password, AuthenticationContext.SystemPrincipal);
                        }
                        else
                        {
                            localIdp.ChangePassword(principal.Identity.Name, password, AuthenticationContext.SystemPrincipal);
                        }

                        // Copy security attributes
                        var localSu = ApplicationContext.Current.GetService <IDataPersistenceService <SecurityUser> >().Get(sid, null, true, AuthenticationContext.SystemPrincipal);
                        localSu.Email         = cprincipal.FindFirst(SanteDBClaimTypes.Email)?.Value;
                        localSu.PhoneNumber   = cprincipal.FindFirst(SanteDBClaimTypes.Telephone)?.Value;
                        localSu.LastLoginTime = DateTime.Now;
                        ApplicationContext.Current.GetService <IDataPersistenceService <SecurityUser> >().Update(localSu, TransactionMode.Commit, AuthenticationContext.SystemPrincipal);

                        // Add user to roles
                        // TODO: Remove users from specified roles?
                        localRp.AddUsersToRoles(new String[] { principal.Identity.Name }, cprincipal.Claims.Where(o => o.Type == SanteDBClaimTypes.DefaultRoleClaimType).Select(o => o.Value).ToArray(), AuthenticationContext.SystemPrincipal);
                        // Unlock the account
                        localIdp.SetLockout(principal.Identity.Name, false, principal);
                    }
                    catch (Exception ex)
                    {
                        this.m_tracer.TraceWarning("Insertion of local cache credential failed: {0}", ex);
                    }
                }
            }
        }