Exemple #1
0
        /// <summary>
        /// Processes the login callback for oidc.
        /// </summary>
        /// <param name="externalResult">The result model got from the external identity server.</param>
        /// <param name="localClaims">The extra claims our identity server can add.</param>
        /// <param name="localSignInProps">Properties that the identity server can add for self use.</param>
        private void ProcessLoginCallbackForOidc(ExternalResult externalResult,
                                                 List <Claim> localClaims,
                                                 AuthenticationProperties localSignInProps)
        {
            // if the external system sent a session id claim, copy it over
            // so we can use it for single sign-out
            Claim sid = externalResult.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);

            if (sid != null)
            {
                localClaims.Add(new Claim(JwtClaimTypes.SessionId, sid.Value));
            }

            // if the external provider issued an id_token, we'll keep it for signout
            string idToken = externalResult.IdToken;

            if (idToken != null)
            {
                localSignInProps.StoreTokens(new[]
                {
                    new AuthenticationToken
                    {
                        Name  = "id_token",
                        Value = idToken
                    }
                });
            }
        }
        public async Task <ExternalResult> ComputeExternalAsync(Matrix <double> m)
        {
            ExternalResult res = new ExternalResult();

            byte[] bytes = await FetchBytesExternalAsync(m);

            int sz           = m.RowCount;
            int origByteSize = sz * sz * FLOAT64BDEPTH;
            int remaining    = bytes.Length - origByteSize;

            res.G = GetMatrixFromBytes(bytes, 0, origByteSize, sz);
            res.D = GetComplexVectorFromBytes(bytes, origByteSize, remaining, sz);
            return(res);
        }
Exemple #3
0
        private async Task <string> GetToken()
        {
            if (string.IsNullOrEmpty(_CurrentToken))
            {
                ExternalResult <string> tokenResult = await RequestToken();

                if (tokenResult.Status == ExternalResultStatus.Error)
                {
                    throw new AuthenticationException(tokenResult.Message);
                }
                _CurrentToken = tokenResult.Payload;
            }

            return(_CurrentToken);
        }
Exemple #4
0
        FindUserFromExternalProvider(ExternalResult result)
        {
            // try to determine the unique id of the external user (issued by the provider)
            // the most common claim type for that are the sub claim and the NameIdentifier
            // depending on the external provider, some other claim type might be used
            Claim userIdClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject) ??
                                result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier) ??
                                throw new Exception("Unknown userid");

            // remove the user id claim so we don't include it as an extra claim if/when we provision the user
            List <Claim> claims = result.Claims.ToList();

            claims.Remove(userIdClaim);

            string provider       = result.Schema;
            string providerUserId = userIdClaim.Value;

            // find external user
            IdentityUser user = await identityUserService.FindByExternalProvider(provider, providerUserId);

            return(user, provider, providerUserId, claims);
        }
Exemple #5
0
        private async Task <ExternalResult <string> > RequestToken()
        {
            ExternalResult <string> tokenResult = new ExternalResult <string>()
            {
                Status = ExternalResultStatus.Error
            };

            _logger.LogDebug("Getting authentication token...");
            using HttpClient client = _httpClientFactory.CreateClient("Pims.Api.Logging");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
            try
            {
                using StringContent credentials = new(JsonSerializer.Serialize(new TokenRequest
                {
                    Username = _config.ConnectionUser,
                    Password = _config.ConnectionPassword
                }), Encoding.UTF8, MediaTypeNames.Application.Json);

                Uri endpoint = new Uri($"{this._config.BaseUri}/auth/token/obtain/");
                HttpResponseMessage response = await client.PostAsync(endpoint, credentials).ConfigureAwait(true);

                string payload = await response.Content.ReadAsStringAsync().ConfigureAwait(true);

                this._logger.LogTrace("Response: {response}", response);
                switch (response.StatusCode)
                {
                case HttpStatusCode.OK:
                    this._logger.LogTrace("Response payload: {payload}", payload);
                    TokenResult requestTokenResult = JsonSerializer.Deserialize <TokenResult>(payload);
                    tokenResult.Status  = ExternalResultStatus.Success;
                    tokenResult.Payload = requestTokenResult.Token;
                    break;

                case HttpStatusCode.NoContent:
                    tokenResult.Status  = ExternalResultStatus.Error;
                    tokenResult.Message = "No token was returned from the call";
                    break;

                case HttpStatusCode.Forbidden:
                    tokenResult.Status  = ExternalResultStatus.Error;
                    tokenResult.Message = "Token request was forbidden";
                    break;

                case HttpStatusCode.BadRequest:
                    tokenResult.Status  = ExternalResultStatus.Error;
                    tokenResult.Message = payload;
                    break;

                default:
                    tokenResult.Status  = ExternalResultStatus.Error;
                    tokenResult.Message = $"Unable to contact endpoint {endpoint}. Http status {response.StatusCode}";
                    break;
                }
            }
            catch (Exception e)
            {
                tokenResult.Status  = ExternalResultStatus.Error;
                tokenResult.Message = "Exception obtaining a token";
                this._logger.LogError("Unexpected exception obtaining a token {e}", e);
            }

            this._logger.LogDebug("Finished getting authentication token");
            return(tokenResult);
        }
Exemple #6
0
        public async Task <IActionResult> Callback(string code, string state, string session_state)
        {
            // Get the return url for the frontend from the cookies.
            string returnUrl = HttpContext.Request.Cookies["returnUrl"];

            HttpContext.Response.Cookies.Delete("returnUrl");

            //Request an accesstoken and idtoken from the authority.
            RestClient  client  = new RestClient(config.FfhictOIDC.Authority + "/connect/token");
            RestRequest request = new RestRequest(Method.POST);

            request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
            request.AddParameter("grant_type", "authorization_code");
            request.AddParameter("code", code);
            request.AddParameter("redirect_uri", config.FfhictOIDC.RedirectUri);
            request.AddParameter("client_id", config.FfhictOIDC.ClientId);
            request.AddParameter("client_secret", config.FfhictOIDC.ClientSecret);
            IRestResponse response = client.Execute(request);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                return(BadRequest("Could not validate the identity server authentication."));
            }

            // Parse the content to get the access token.
            ExternalConnectToken fhictToken = JsonConvert.DeserializeObject <ExternalConnectToken>(response.Content);

            if (string.IsNullOrWhiteSpace(fhictToken.AccessToken))
            {
                throw new Exception("The FHICT didn't return a correct response. Is the FHICT server accessible?", new Exception("Content:\n" + response.Content + "\n\nError:\n" + response.ErrorMessage, response.ErrorException));
            }

            JwtSecurityToken jwt = new JwtSecurityToken(fhictToken.AccessToken);
            string           idp = (string)jwt.Payload.FirstOrDefault(c => c.Key.Equals("idp")).Value;
            string           iss = (string)jwt.Payload.FirstOrDefault(c => c.Key.Equals("iss")).Value;

            ExternalResult result = new ExternalResult
            {
                Schema    = iss,
                Claims    = jwt.Claims,
                ReturnUrl = returnUrl,
                IdToken   = fhictToken.IdToken
            };

            // lookup our user and external provider info
            (IdentityUser user, string provider, string providerUserId, IEnumerable <Claim> claims) = await FindUserFromExternalProvider(result);

            if (user == null)
            {
                //Retrieve more user information from the external source.
                // Get User information
                RestClient  informationClient  = new RestClient($"{iss}/connect/userinfo");
                RestRequest informationRequest = new RestRequest(Method.GET);
                informationRequest.AddHeader("Authorization", $"Bearer {fhictToken.AccessToken}");
                IRestResponse    informationResponse = informationClient.Execute(informationRequest);
                ExternalUserInfo userinfo            = JsonConvert.DeserializeObject <ExternalUserInfo>(informationResponse.Content);

                List <Claim> claimsList = claims.ToList();
                claimsList.Add(new Claim("email", userinfo.PreferredUsername));
                claimsList.Add(new Claim("idp", idp));
                claimsList.Add(new Claim("name", userinfo.Name));
                IdentityUser toInsertuser = new IdentityUser()
                {
                    ProviderId        = provider,
                    ExternalSubjectId = providerUserId,
                    Email             = userinfo.Email,
                    Firstname         = userinfo.GivenName,
                    Lastname          = userinfo.FamilyName,
                    Name               = userinfo.Name,
                    Username           = userinfo.PreferredUsername,
                    ExternalProfileUrl = userinfo.Profile
                };

                // simply auto-provisions new external user
                user = await identityUserService.AutoProvisionUser(toInsertuser);
            }

            // this allows us to collect any additional claims or properties
            // for the specific protocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            List <Claim>             additionalLocalClaims = new List <Claim>();
            AuthenticationProperties localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            IdentityServerUser isuser = new IdentityServerUser(user.SubjectId)
            {
                DisplayName      = user.Name,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };

            await HttpContext.SignInAsync(isuser, localSignInProps).ConfigureAwait(false);

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme).ConfigureAwait(false);

            // check if external login is in the context of an OIDC request
            AuthorizationRequest context = await interaction.GetAuthorizationContextAsync(returnUrl).ConfigureAwait(false);

            await events.RaiseAsync(new UserLoginSuccessEvent(provider,
                                                              providerUserId,
                                                              user.SubjectId,
                                                              user.Username,
                                                              true,
                                                              context?.ClientId)).ConfigureAwait(false);

            if (context != null)
            {
                if (await clientStore.IsPkceClientAsync(context.ClientId).ConfigureAwait(false))
                {
                    // if the client is PKCE then we assume it's native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(this.LoadingPage("Redirect", returnUrl));
                }
            }

            return(Redirect(returnUrl));
        }