Ejemplo n.º 1
0
 /// <summary>
 ///   Unisce i due URI dati.
 /// </summary>
 /// <param name="baseUri">Il primo URI.</param>
 /// <param name="relativePath">Il secondo URI.</param>
 /// <param name="queryStringBuilder">La componente della query string.</param>
 /// <returns>I due URI uniti.</returns>
 private static string UriCombine(string baseUri, PathString relativePath, QueryStringBuilder queryStringBuilder = null)
 {
     var trimmedBaseUri = baseUri.TrimEnd(UrlTrimChars);
     var trimmedRelativePathValue = relativePath.HasValue ? relativePath.Value.TrimStart(UrlTrimChars) : string.Empty;
     return string.Format("{0}/{1}{2}", trimmedBaseUri, trimmedRelativePathValue, queryStringBuilder?.ToString() ?? string.Empty);
 }
Ejemplo n.º 2
0
        /// <summary>
        ///   Gestisce l'handler di tipo REDIRECT per LOGIN, che si occupa di generare i token dopo
        ///   la login.
        /// </summary>
        /// <param name="owinContext">Il contesto di OWIN.</param>
        /// <returns>Un task.</returns>
        private async Task HandleLoginRedirectAsync(IOwinContext owinContext)
        {
            // Recupero le informazioni su request e response.
            var owinRequest = owinContext.Request;
            var owinResponse = owinContext.Response;

            string authCode;
            switch (owinRequest.Method)
            {
                case "GET":
                case "get":
                    Raise.InvalidOperationException.If(_settings.ResponseMode != OAuth2ResponseMode.FragmentEncodedRedirect);
                    // Visto che il flusso utilizzato è di tipo "code grant", mi aspetto che nel
                    // query string sia presenta il codice "code" per proseguire il flusso.
                    authCode = owinRequest.Query["code"];
                    break;

                case "POST":
                case "post":
                    Raise.InvalidOperationException.If(_settings.ResponseMode != OAuth2ResponseMode.FormPost);
                    // Visto che il flusso utilizzato è di tipo "code grant", mi aspetto che il query
                    // string mi sia stato inviato in POST.
                    using (var sr = new StreamReader(owinRequest.Body))
                    {
                        var qs = new QueryStringBuilder(await sr.ReadToEndAsync());
                        authCode = qs["code"];
                    }
                    break;

                default:
                    throw new NotSupportedException($"HTTP method {owinRequest.Method} is not supported for redirect");
            }

            // Recupero i token tramite l'authorization code appena ricevuto.
            var oauth2TokensGenRes = await _authCodeHandler.RequestTokensAsync(owinContext, _settings.ClientId, authCode);

            var userValidationResult = await _userValidator.ValidateAsync(owinContext, _settings.ClientId, oauth2TokensGenRes);
            if (!userValidationResult.Authorized)
            {
                // Effetto il redirect verso la pagina di errore ed esco dal componente di middleware.
                await HandleErrorRedirectAsync(owinContext, userValidationResult.AuthorizationDeniedException, userValidationResult.AuthorizationDeniedReason);
                return;
            }

            // Preparo il cookie con i token.
            var oauth2TokensCookie = oauth2TokensGenRes.TokensCookie;
            var oauth2TokensCookieContent = await _tokensCookieEncoder.EncodeAsync(oauth2TokensCookie);

            // Preparo il cookie di verifica.
            var oauth2CsrfCookie = new OAuth2CsrfCookie
            {
                RandomToken = oauth2TokensCookie.RandomToken
            };
            var oauth2CsrfCookieContent = await _csrfCookieEncoder.EncodeAsync(oauth2CsrfCookie);

            // Elaboro le date di fine dei token e dei cookie.
            var accessTokenExpiresOn = oauth2TokensCookie.AccessTokenCreatedOn.AddSeconds(oauth2TokensCookie.AccessTokenExpiresIn);

            // Aggiungo il cookie con i token alla response.
            owinResponse.Cookies.Append(OAuth2TokensCookie.CookieName, oauth2TokensCookieContent, new CookieOptions
            {
                HttpOnly = true, // Fondamentale che NON sia accessibile da JavaScript.
                Expires = accessTokenExpiresOn
            });

            // Aggiungo il cookie di verifica per evitare XSRF.
            owinResponse.Cookies.Append(OAuth2CsrfCookie.CookieName, oauth2CsrfCookieContent, new CookieOptions
            {
                HttpOnly = false, // Fondamentale che SIA accessibile anche da JavaScript.
                Expires = accessTokenExpiresOn
            });

            // Aggiungo il cookie con l'identity token, se presente.
            if (oauth2TokensGenRes.IdentityToken.HasValue)
            {
                // Non imposto data di scadenza, in quanto è un cookie di sessione.
                owinResponse.Cookies.Append(IdentityTokenCookieName, oauth2TokensGenRes.IdentityToken.Value, new CookieOptions
                {
                    HttpOnly = true, // Non deve essere visto da JavaScript.
                });
            }

            // Effettuo il redirect verso la pagina specificata ed esco dal componente di middleware.
            owinResponse.Redirect(_settings.RedirectUri.AbsoluteUri);
        }
Ejemplo n.º 3
0
        /// <summary>
        ///   Gestisce l'handler di tipo LOGOUT, che redirige tutte le chiamate verso il portale di OAuth2.
        /// </summary>
        /// <param name="owinContext">Il contesto di OWIN.</param>
        /// <returns>Un task.</returns>
        private Task HandleLogoutAsync(IOwinContext owinContext)
        {
            // Recupero le informazioni su request e response.
            var owinRequest = owinContext.Request;
            var owinResponse = owinContext.Response;

            var identityTokenCookieContent = owinRequest.Cookies[IdentityTokenCookieName];
            if (_settings.PerformEndSessionRedirect && !string.IsNullOrWhiteSpace(identityTokenCookieContent))
            {
                // Normalizzo l'indirizzo della request per poi effettuare la trasformazione da
                // "/logout" a "/logoutRedirect", al fine di avere l'indirizzo giusto per il
                // parametro "post_logout_redirect_uri".
                var lowerRequestUri = owinRequest.Uri.AbsoluteUri.ToLowerInvariant().TrimEnd(UrlTrimChars);
                var postLogoutRedirectUri = lowerRequestUri.Replace(LogoutPath, LogoutRedirectPath);

                // Preparo il query string richiesto da "endsession".
                var qsBuilder = new QueryStringBuilder()
                    .Add("id_token_hint", identityTokenCookieContent)
                    .Add("post_logout_redirect_uri", postLogoutRedirectUri);

                // Effettuo il redirect ed esco dal componente di middleware.
                var url = UriCombine(_settings.OAuth2EndpointUri.AbsoluteUri, _settings.EndSessionPath, qsBuilder);
                _log.Debug($"Performing redirect to {url}");
                owinResponse.Redirect(url);
                return TaskHelper.CompletedTask;
            }

            // Effettuo il redirect verso la pagina indicata ed esco dal componente di middleware.
            return HandleLogoutRedirectAsync(owinContext);
        }
Ejemplo n.º 4
0
        /// <summary>
        ///   Gestisce l'handler di tipo LOGIN, che redirige tutte le chiamate verso il portale di OAuth2.
        /// </summary>
        /// <param name="owinRequest">La richiesta OWIN.</param>
        /// <param name="owinResponse">La risposta OWIN.</param>
        /// <returns>Un task.</returns>
        private Task HandleLoginAsync(IOwinRequest owinRequest, IOwinResponse owinResponse)
        {
            // Faccio la decodifica del tipo del flusso.
            string responseType;
            switch (_settings.ResponseType)
            {
                case OAuth2ResponseType.AuthorizationCode:
                    responseType = "code";
                    break;

                case OAuth2ResponseType.IdentityTokenAndAccessToken:
                    responseType = "id_token token";
                    break;

                case OAuth2ResponseType.Hybrid:
                    responseType = "code id_token token";
                    break;

                default:
                    responseType = "token";
                    break;
            }

            // Normalizzo l'indirizzo della request per poi effettuare la trasformazione da "/login"
            // a "/loginRedirect", al fine di avere l'indirizzo giusto per il parametro "redirect_uri".
            var lowerRequestUri = owinRequest.Uri.AbsoluteUri.ToLowerInvariant().TrimEnd(UrlTrimChars);
            var redirectUri = lowerRequestUri.Replace(LoginPath, LoginRedirectPath);

            // Costruisce l'indirizzo a cui fare redirect.
            var qsBuilder = new QueryStringBuilder()
                .Add("client_id", _settings.ClientId)
                .Add("redirect_uri", redirectUri)
                .Add("response_type", responseType);

            if (_settings.Scopes != null && _settings.Scopes.Count > 0)
            {
                qsBuilder.Add("scope", string.Join(" ", _settings.Scopes));
            }

            if (_settings.NonceGenerationMode == OAuth2NonceGenerationMode.Auto)
            {
                qsBuilder.Add("nonce", UniqueIdGenerator.NewBase32("-"));
            }

            if (_settings.ResponseMode == OAuth2ResponseMode.FormPost)
            {
                qsBuilder.Add("response_mode", "form_post");
            }

            // Effettuo il redirect ed esco dal componente di middleware.
            var url = UriCombine(_settings.OAuth2EndpointUri.AbsoluteUri, _settings.AuthorizePath, qsBuilder);
            _log.Debug($"Performing redirect to {url}");
            owinResponse.Redirect(url);
            return TaskHelper.CompletedTask;
        }