Example #1
0
        private static async Task <SessionAuthorizationTransaction> GenerateTransaction(
            IJSRuntime jsRuntime,
            AuthorizeOptions authorizeOptions,
            bool responseTypeIncludesIdToken)
        {
            string lastUsedConnection = string.IsNullOrEmpty(authorizeOptions.Realm) ? authorizeOptions.Connection : authorizeOptions.Realm;

            string appState = string.IsNullOrEmpty(authorizeOptions.AppState) ? CommonAuthentication.GenerateNonce(authorizeOptions.KeyLength) : authorizeOptions.AppState;

            authorizeOptions.State = string.IsNullOrEmpty(authorizeOptions.State) ? CommonAuthentication.GenerateNonce(authorizeOptions.KeyLength) : authorizeOptions.State;
            string nonce = responseTypeIncludesIdToken ? string.IsNullOrEmpty(authorizeOptions.Nonce) ? CommonAuthentication.GenerateNonce(authorizeOptions.KeyLength) : authorizeOptions.Nonce : null;

            SessionAuthorizationTransaction transaction = new SessionAuthorizationTransaction()
            {
                Nonce        = nonce,
                AppState     = appState,
                State        = authorizeOptions.State,
                CodeVerifier = authorizeOptions.CodeVerifier,
                RedirectUri  = authorizeOptions.RedirectUri,
                Connnection  = lastUsedConnection,
            };

            await Storage.SetItem(
                jsRuntime,
                $"{authorizeOptions.Namespace}{authorizeOptions.State}",
                transaction
                ).ConfigureAwait(false);

            return(transaction);
        }
Example #2
0
        /// <summary>
        /// Builds the an authorization URI.
        /// </summary>
        /// <param name="buildAuthorizedUrlOptions">A <see cref="AuthorizeOptions"/> param.</param>
        /// <returns>An <see cref="string"/> representing an authorization URI.</returns>
        public static string BuildAuthorizeUrl(AuthorizeOptions buildAuthorizedUrlOptions)
        {
            if (buildAuthorizedUrlOptions is null)
            {
                throw new ArgumentNullException(nameof(buildAuthorizedUrlOptions));
            }

            Utils.ValidateObject(buildAuthorizedUrlOptions);

            var responseType = CommonAuthentication.ParseResponseType(buildAuthorizedUrlOptions.ResponseType);
            var responseMode = CommonAuthentication.ParseResponseMode(buildAuthorizedUrlOptions.ResponseMode);

            var path  = new PathString("/authorize");
            var query = new QueryString();

            query = query.Add("response_type", responseType);
            query = query.Add("state", buildAuthorizedUrlOptions.State);
            query = query.Add("nonce", buildAuthorizedUrlOptions.Nonce);
            query = query.Add("client_id", buildAuthorizedUrlOptions.ClientID);
            query = query.Add("scope", buildAuthorizedUrlOptions.Scope);

            if (buildAuthorizedUrlOptions.CodeChallengeMethod != CodeChallengeMethods.None)
            {
                string codechallengeMethod = CommonAuthentication.ParseCodeChallengeMethod(buildAuthorizedUrlOptions.CodeChallengeMethod);

                query = query.Add("code_challenge_method", codechallengeMethod);
                query = query.Add("code_challenge", buildAuthorizedUrlOptions.CodeChallenge);
            }

            if (!string.IsNullOrEmpty(buildAuthorizedUrlOptions.Connection))
            {
                query = query.Add("connection", buildAuthorizedUrlOptions.Connection);
            }

            if (!string.IsNullOrEmpty(buildAuthorizedUrlOptions.Audience))
            {
                query = query.Add("audience", buildAuthorizedUrlOptions.Audience);
            }

            if (!string.IsNullOrEmpty(responseMode))
            {
                query = query.Add("response_mode", responseMode);
            }

            query = query.Add("redirect_uri", buildAuthorizedUrlOptions.RedirectUri);

            UriBuilder uriBuilder = new UriBuilder
            {
                Scheme = "https",
                Host   = buildAuthorizedUrlOptions.Domain,
                Path   = path,
                Query  = query.ToUriComponent(),
            };

            return(uriBuilder.Uri.AbsoluteUri);
        }
        /// <summary>
        /// Add default Blazor.Auth0 authentication.
        /// </summary>
        /// <param name="services">The <see cref="IServiceCollection"/> instance.</param>
        public static void AddDefaultBlazorAuth0Authentication(this IServiceCollection services)
        {
            // TODO: This method is too convulted, it should be separeted into smaller pieces
            if (services is null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            ClientOptions clientOptions = services.BuildServiceProvider().GetRequiredService <ClientOptions>();

            Utils.ValidateObject(clientOptions);

            services.Configure <CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded    = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme       = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme    = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.ExpireTimeSpan    = TimeSpan.FromMinutes(60);
                options.SlidingExpiration = clientOptions.SlidingExpiration;
            })
            .AddBlazorAuth0()
            .AddOpenIdConnect(clientOptions.ClaimsIssuer, options =>
            {
                // Set the authority to your Auth0 domain
                options.Authority            = $"https://{clientOptions.Domain}";
                options.RequireHttpsMetadata = false;

                // Configure the Auth0 Client ID and Client Secret
                options.ClientId     = clientOptions.ClientId;
                options.ClientSecret = clientOptions.ClientSecret;

                options.ResponseType = CommonAuthentication.ParseResponseType(clientOptions.ResponseType);

                string[] scopes = clientOptions.Scope.Trim().ToLowerInvariant().Split(",");

                options.Scope.Clear();

                foreach (string scope in scopes)
                {
                    options.Scope.Add(scope);
                }

                if (clientOptions.ResponseType == Models.Enumerations.ResponseTypes.Code && !string.IsNullOrEmpty(clientOptions.ClientSecret))
                {
                    options.Scope.Add("offline_access");
                }

                options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash");

                options.GetClaimsFromUserInfoEndpoint = true;
                options.SaveTokens        = true;
                options.CallbackPath      = new PathString(clientOptions.CallbackPath);
                options.RemoteSignOutPath = new PathString(clientOptions.RemoteSignOutPath);

                options.SignedOutRedirectUri = clientOptions.RedirectUri;

                options.ClaimsIssuer = clientOptions.ClaimsIssuer;

                options.UseTokenLifetime = !clientOptions.SlidingExpiration;

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType         = "name",
                    RoleClaimType         = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
                    RequireSignedTokens   = true,
                    RequireExpirationTime = true,
                    ValidateTokenReplay   = true,
                    ValidIssuers          = new string[]
                    {
                        options.Authority,
                    },
                    ValidateLifetime         = true,
                    ValidateIssuerSigningKey = true,
                };

                if (!string.IsNullOrEmpty(clientOptions.Audience))
                {
                    options.TokenValidationParameters.ValidAudiences = new string[] {
                        clientOptions.Audience,
                        $"{options.Authority}/userinfo",
                    };
                }

                options.Events = new OpenIdConnectEvents
                {
                    OnRedirectToIdentityProvider = context =>
                    {
                        if (!string.IsNullOrEmpty(clientOptions.Audience))
                        {
                            context.ProtocolMessage.SetParameter("audience", clientOptions.Audience);

                            HttpRequest request = context.Request;
                            var errorUri        = request.Scheme + "://" + request.Host + request.PathBase;
                            context.ProtocolMessage.SetParameter("error_uri", errorUri);
                        }

                        return(Task.FromResult(0));
                    },

                    OnRemoteSignOut = (context) =>
                    {
                        Authentication.ClearAspNetCookies(context.HttpContext);

                        string redirectUri = context.Request.Query
                                             .Where(x => x.Key.ToLowerInvariant() == "redirect_uri")
                                             .Select(x => x.Value)
                                             .FirstOrDefault();

                        if (string.IsNullOrEmpty(redirectUri))
                        {
                            HttpRequest request = context.Request;
                            redirectUri         = request.Scheme + "://" + request.Host + request.PathBase;
                        }

                        string logoutUri = CommonAuthentication.BuildLogoutUrl(clientOptions.Domain, clientOptions.ClientId, redirectUri);

                        context.Response.Redirect(logoutUri);

                        context.HandleResponse();

                        return(Task.CompletedTask);
                    },

                    // handle the logout redirection
                    OnRedirectToIdentityProviderForSignOut = (context) =>
                    {
                        string logoutUri = CommonAuthentication.BuildLogoutUrl(clientOptions.Domain, clientOptions.ClientId);

                        string postLogoutUri = context.Properties.RedirectUri;
                        if (!string.IsNullOrEmpty(postLogoutUri))
                        {
                            if (postLogoutUri.StartsWith("/"))
                            {
                                // transform to absolute
                                HttpRequest request = context.Request;
                                postLogoutUri       = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                            }

                            logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
                        }

                        context.Response.Redirect(logoutUri);
                        context.HandleResponse();

                        return(Task.CompletedTask);
                    },
                    OnTokenValidated = (u) =>
                    {
                        if (!string.IsNullOrEmpty(clientOptions.Audience))
                        {
                            string accessToken = u.TokenEndpointResponse.AccessToken;
                            AccessTokenPayload parsedAccessToken = !string.IsNullOrEmpty(accessToken) ? CommonAuthentication.DecodeTokenPayload <AccessTokenPayload>(accessToken) : default;
                            List <string> permissions            = parsedAccessToken?.Permissions ?? new List <string>();

                            if (permissions.Any())
                            {
                                string name = u.Principal.Claims.Where(x => x.Type == "name").FirstOrDefault()?.Value;
                                name ??= u.Principal.Claims.Where(x => x.Type == ClaimTypes.GivenName).FirstOrDefault()?.Value;
                                name ??= u.Principal.Claims.Where(x => x.Type == ClaimTypes.Name).FirstOrDefault()?.Value;
                                name ??= u.Principal.Claims.Where(x => x.Type == "nickname").FirstOrDefault()?.Value;
                                name ??= u.Principal.Claims.Where(x => x.Type == ClaimTypes.Email).FirstOrDefault()?.Value;

                                GenericIdentity identity = new GenericIdentity(name, "JWT");

                                identity.AddClaims(u.Principal.Claims);

                                identity.AddClaims(permissions.Select(permission => new Claim("permissions", permission, "permissions")));

                                identity.AddClaim(new Claim("exp", parsedAccessToken.Exp.ToString(), ClaimValueTypes.Integer64));

                                ClaimsPrincipal user = new ClaimsPrincipal(identity);

                                u.Principal = user;
                            }
                        }

                        return(Task.CompletedTask);
                    },
                    OnAccessDenied = (u) =>
                    {
                        return(Task.CompletedTask);
                    },
                    OnAuthenticationFailed = (u) =>
                    {
                        return(Task.CompletedTask);
                    },
                    OnRemoteFailure = (context) =>
                    {
                        context.Response.Redirect("/");
                        context.HandleResponse();

                        return(Task.CompletedTask);
                    },
                };
            });