Esempio n. 1
0
        private static void ConfigureExternalAuthenticationServices(AuthenticationBuilder authenticationBuilder, TenantsBuilder tenantsBuilder, IConfiguration configuration)
        {
            if (tenantsBuilder != null)
            {
                authenticationBuilder.AddOpenIdConnect(IdentityCoreConstants.ExternalOidcScheme, openIdConnect =>
                {
                    // will be configured dynamically

                    openIdConnect.ClientId  = "N/A";
                    openIdConnect.Authority = "https://nowhere.nowhere";
                });

                tenantsBuilder.WithPerTenantOptions <OpenIdConnectOptions>((openIdConnect, tenantInfo) =>
                {
                    if (string.Equals(tenantInfo.ExternalAuthenticationMethod, TenantConstants.ExternalAuthenticationMethodOidc))
                    {
                        var oidcClientId     = tenantInfo.OidcClientId;
                        var oidcClientSecret = tenantInfo.OidcClientSecret;
                        var oidcEndpointUrl  = tenantInfo.OidcEndpointUrl;

                        openIdConnect.SignInScheme  = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                        openIdConnect.SignOutScheme = IdentityServerConstants.SignoutScheme;

                        openIdConnect.Authority = oidcEndpointUrl;

                        openIdConnect.ClientId     = oidcClientId;
                        openIdConnect.ClientSecret = oidcClientSecret;

                        // make sure we get user group membership information

                        openIdConnect.GetClaimsFromUserInfoEndpoint = true;

                        openIdConnect.Scope.Add("openid");
                        openIdConnect.Scope.Add("email");
                        openIdConnect.Scope.Add("phone");
                        openIdConnect.Scope.Add("profile");
                    }
                });

                authenticationBuilder.AddSaml2(IdentityCoreConstants.ExternalSamlScheme, saml =>
                {
                    // will be configured dynamically
                });

                tenantsBuilder.WithPerTenantOptions <Saml2Options>((saml, tenantInfo) =>
                {
                    if (string.Equals(tenantInfo.ExternalAuthenticationMethod, TenantConstants.ExternalAuthenticationMethodSaml))
                    {
                        var samlEntityId         = tenantInfo.SamlEntityId;
                        var samlMetadataLocation = tenantInfo.SamlMetadataLocation;

                        var samlProviderUrl = tenantInfo.SamlProviderUrl;

                        var samlCertificate = tenantInfo.SamlCertificate;

                        saml.SPOptions.EntityId = new EntityId(samlEntityId);

                        if (tenantInfo.SamlAllowWeakSigningAlgorithm)
                        {
                            // OK this is less secure, but sometimes we're having trouble
                            // e.g. with SSO Circle that still uses SHA1

                            saml.SPOptions.MinIncomingSigningAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
                        }

                        saml.IdentityProviders.Add(
                            new IdentityProvider(new EntityId(samlProviderUrl), saml.SPOptions)
                        {
                            LoadMetadata     = true,
                            MetadataLocation = samlMetadataLocation
                        }
                            );

                        if (samlCertificate != null)
                        {
                            saml.SPOptions.ServiceCertificates.Add(new ServiceCertificate()
                            {
                                Certificate = samlCertificate,
                                Use         = CertificateUse.Signing
                            });
                        }

                        saml.SignInScheme  = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                        saml.SignOutScheme = IdentityServerConstants.SignoutScheme;
                    }
                });
            }
        }
Esempio n. 2
0
        private static void ConfigureJwtAuthentication(IServiceCollection services, TenantsBuilder tenantsBuilder, IConfiguration configuration)
        {
            var authenticationBuilder = services.AddAuthentication();

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            string[] requiredScopesSplit = null;

            string requiredScopes = configuration["Identity:Jwt:RequiredScopes"];

            if (!string.IsNullOrEmpty(requiredScopes))
            {
                requiredScopesSplit = requiredScopes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                if (requiredScopesSplit.Length == 0)
                {
                    requiredScopesSplit = null;
                }
            }

            if (tenantsBuilder == null)
            {
                string defaultClientAuthority = configuration[$"Identity:DefaultClient:Authority"];
                if (string.IsNullOrEmpty(defaultClientAuthority))
                {
                    throw new Exception("Identity default client authority string is empty");
                }

                string defaultClientAudience = configuration[$"Identity:DefaultClient:Audience"];
                if (string.IsNullOrEmpty(defaultClientAudience))
                {
                    throw new Exception("Identity default client audience string is empty");
                }

                authenticationBuilder.AddJwtBearer(IdentityCoreConstants.JwtScheme, jwt =>
                {
                    jwt.RequireHttpsMetadata = true;

                    jwt.Authority = defaultClientAuthority;
                    jwt.Audience  = defaultClientAudience;

                    jwt.TokenValidationParameters = new TokenValidationParameters()
                    {
                        ClockSkew             = TimeSpan.FromMinutes(5),
                        RequireSignedTokens   = true,
                        RequireExpirationTime = true,
                        ValidateLifetime      = true,
                        // audience validation will be done via scope, as recommended in
                        // https://github.com/IdentityServer/IdentityServer4/issues/127
                        ValidateAudience = false,
                        ValidateIssuer   = true,
                        ValidIssuer      = defaultClientAuthority
                    };
                });

                services.AddAuthorization(options =>
                {
                    options.AddPolicy(IdentityCoreConstants.JwtPolicy, policy =>
                    {
                        policy.AuthenticationSchemes.Add(IdentityCoreConstants.JwtScheme);

                        if (requiredScopesSplit != null)
                        {
                            policy.RequireAssertion(handler =>
                            {
                                return(CheckScopes(handler.User, requiredScopesSplit));
                            });
                        }

                        policy.RequireAuthenticatedUser();
                    });
                });
            }
            else
            {
                authenticationBuilder.AddJwtBearer(IdentityCoreConstants.JwtScheme, jwt =>
                {
                    jwt.RequireHttpsMetadata = true;
                });

                tenantsBuilder.WithPerTenantOptions <JwtBearerOptions>((jwt, tenantInfo) =>
                {
                    jwt.Authority = tenantInfo.DeveloperAuthority;
                    jwt.Audience  = tenantInfo.DeveloperAudience;

                    var tokenValidationParameters = new TokenValidationParameters()
                    {
                        ClockSkew             = TimeSpan.FromMinutes(5),
                        RequireSignedTokens   = true,
                        RequireExpirationTime = true,
                        ValidateLifetime      = true,
                        // audience validation will be done via scope, as recommended in
                        // https://github.com/IdentityServer/IdentityServer4/issues/127
                        ValidateAudience = false,
                        ValidateIssuer   = true,
                        ValidIssuer      = tenantInfo.DeveloperAuthority
                    };

                    if (tenantInfo.DeveloperCertificate != null)
                    {
                        // if we cannot resolve it from some discovery endpoint

                        tokenValidationParameters.IssuerSigningKey = new X509SecurityKey(tenantInfo.DeveloperCertificate);
                    }

                    jwt.TokenValidationParameters = tokenValidationParameters;
                });

                ConfigureExternalAuthenticationServices(authenticationBuilder, tenantsBuilder, configuration);

                services.AddAuthorization(options =>
                {
                    options.AddPolicy(IdentityCoreConstants.JwtPolicy, policy =>
                    {
                        policy.AuthenticationSchemes.Add(IdentityCoreConstants.JwtScheme);

                        policy.Requirements.Add(new ClientDeveloperUuidRequirement());

                        if (requiredScopesSplit != null)
                        {
                            policy.RequireAssertion(handler =>
                            {
                                return(CheckScopes(handler.User, requiredScopesSplit));
                            });
                        }

                        policy.RequireAuthenticatedUser();
                    });
                });

                services.AddSingleton <IAuthorizationHandler, ClientDeveloperUuidRequirementHandler>();
            }
        }