示例#1
0
        public override async Task Authorize(HttpContext context)
        {
            // get the necessary variables
            string authority  = CasConfig.AzureAuthority;
            string clientId   = WebUtility.UrlEncode(CasConfig.AzureClientId);
            string redirect   = WebUtility.UrlEncode(CasConfig.RedirectUri(context.Request));
            string domainHint = WebUtility.UrlEncode(CasConfig.AzureDomainHint);

            // get the scope
            var basicScope = "openid profile email";
            var scope      = await AppendScope(basicScope, "microsoft.com");

            // define the response type
            string responseType = (scope == basicScope)
                ? WebUtility.UrlEncode("id_token")
                : WebUtility.UrlEncode("id_token code");

            // write flow cookie
            var flow = WriteFlowCookie(context);

            // redirect to url
            scope = WebUtility.UrlEncode(scope);
            string url = $"{authority}/oauth2/v2.0/authorize?response_type={responseType}&client_id={clientId}&redirect_uri={redirect}&scope={scope}&response_mode=form_post&state={flow.state}&nonce={flow.nonce}";

            if (!string.IsNullOrEmpty(domainHint))
            {
                url += $"&domain_hint={domainHint}";
            }
            context.Response.Redirect(url);
            await context.Response.CompleteAsync();
        }
示例#2
0
        private async Task <Tokens> GetAccessTokenFromAuthCode(HttpContext context, string code, string scope)
        {
            // get the client secret
            var secret = await Config.AzureClientSecret();

            // get the response
            using (var request = new HttpRequestMessage()
            {
                RequestUri = new Uri($"{CasConfig.AzureAuthority}/oauth2/v2.0/token"),
                Method = HttpMethod.Post
            })
            {
                using (request.Content = new FormUrlEncodedContent(new[] {
                    new KeyValuePair <string, string>("client_id", CasConfig.AzureClientId),
                    new KeyValuePair <string, string>("client_secret", secret),
                    new KeyValuePair <string, string>("scope", scope),
                    new KeyValuePair <string, string>("code", code),
                    new KeyValuePair <string, string>("redirect_uri", CasConfig.RedirectUri(context.Request)),
                    new KeyValuePair <string, string>("grant_type", "authorization_code")
                }))
                {
                    using (var response = await HttpClient.SendAsync(request))
                    {
                        var raw = await response.Content.ReadAsStringAsync();

                        if (!response.IsSuccessStatusCode)
                        {
                            throw new Exception($"GetAccessTokenFromAuthCode: HTTP {(int)response.StatusCode} - {raw}");
                        }
                        var tokens = JsonConvert.DeserializeObject <Tokens>(raw);
                        return(tokens);
                    }
                }
            };
        }
示例#3
0
        public override async Task Authorize(HttpContext context)
        {
            // get the necessary variables
            string authority = "https://accounts.google.com";
            string clientId  = WebUtility.UrlEncode(CasConfig.GoogleClientId);
            string redirect  = WebUtility.UrlEncode(
                // NOTE: google sends the values on a filter, so we need to extract via javascript
                CasConfig.RedirectUri(context.Request).Replace("/cas/token", "/cas/extract")
                );
            string domainHint = WebUtility.UrlEncode(CasConfig.GoogleDomainHint);

            // get the scope
            var basicScope = "openid profile email";
            var scope      = await AppendScope(basicScope, "google.com");

            // define the response type
            string responseType = (scope == basicScope)
                ? WebUtility.UrlEncode("id_token")
                : WebUtility.UrlEncode("id_token code");

            // NOTE: I have not tested authcode flow with google yet
            if (scope != basicScope)
            {
                throw new System.NotSupportedException();
            }

            // write flow cookie
            var flow = WriteFlowCookie(context);

            // redirect to url
            scope = WebUtility.UrlEncode(scope);
            string url = $"{authority}/o/oauth2/v2/auth?response_type={responseType}&client_id={clientId}&redirect_uri={redirect}&scope={scope}&state={flow.state}&nonce={flow.nonce}";

            if (!string.IsNullOrEmpty(domainHint))
            {
                url += $"&hd={domainHint}";
            }
            context.Response.Redirect(url);
            await context.Response.CompleteAsync();
        }
        public static async Task AddCasServerAuthAsync(this IServiceCollection services)
        {
            // add the logger
            services.AddSingleLineConsoleLogger();

            // add HttpClients
            services.AddHttpClient("netbricks")
            .ConfigurePrimaryHttpMessageHandler(() => new CasProxyHandler());
            services.AddHttpClient("cas")
            .ConfigurePrimaryHttpMessageHandler(() => new CasProxyHandler());

            // add the access token fetcher
            services.AddAccessTokenFetcher();

            // add the configuration service
            services.TryAddSingleton <IConfig, CasConfig>();

            // load the configuration and log it
            using (var provider = services.BuildServiceProvider())
            {
                var logger           = provider.GetService <ILogger <CasServerAuthServicesConfiguration> >();
                var authCodeReceiver = provider.GetService <ICasAuthCodeReceiver>();

                // get the config
                var config = provider.GetService <IConfig>() as CasConfig;
                if (config == null)
                {
                    throw new Exception("AddCasClientAuth: CasConfig could not be found in the IServiceCollection.");
                }

                // determine the authentication type
                var authType = config.AuthType();
                if (authType == AuthTypes.Service)
                {
                    logger.LogInformation("authentication: application ClientId and ClientSecret (service principal).");
                }
                if (authType == AuthTypes.Token)
                {
                    logger.LogInformation("authentication: managed identity with failback to az cli.");
                }

                // load the configuration
                logger.LogInformation("Loading configuration...");
                await config.Apply();

                // confirm and log the configuration
                config.Optional("AUTH_TYPE", authType.ToString());
                config.Optional("AUTH_TYPE_CONFIG", config.AuthType("CONFIG").ToString());
                config.Optional("AUTH_TYPE_VAULT", config.AuthType("VAULT").ToString());
                config.Optional("AUTH_TYPE_GRAPH", config.AuthType("GRAPH").ToString());
                config.Require("AZURE_TENANT_ID", CasConfig.AzureTenantId);
                config.Require("AZURE_CLIENT_ID", CasConfig.AzureClientId);
                if (authType == AuthTypes.Service || authCodeReceiver != null)
                {
                    config.Require("AZURE_CLIENT_SECRET", await config.AzureClientSecret(), hideValue: true);
                }
                else
                {
                    config.Optional("AZURE_CLIENT_SECRET", await config.AzureClientSecret(), hideValue: true);
                }
                config.Optional("APPCONFIG", CasConfig.AppConfig, hideIfEmpty: true);
                config.Optional("CONFIG_KEYS", CasConfig.ConfigKeys, hideIfEmpty: true);
                config.Optional("PROXY", CasConfig.Proxy, hideIfEmpty: true);
                config.Optional("DEFAULT_HOST_URL", CasConfig.DefaultHostUrl, hideIfEmpty: true);
                config.Optional("SERVER_HOST_URL", CasConfig.ServerHostUrl, hideIfEmpty: true);
                config.Optional("CLIENT_HOST_URL", CasConfig.ClientHostUrl, hideIfEmpty: true);
                config.Optional("WEB_HOST_URL", CasConfig.WebHostUrl, hideIfEmpty: true);
                config.Optional("USE_INSECURE_DEFAULTS", CasConfig.UseInsecureDefaults, hideValue: false);
                config.Optional("IS_HTTPS", CasConfig.IsHttps, hideValue: false);
                config.Require("AZURE_AUTHORITY", CasConfig.AzureAuthority);
                config.Optional("GOOGLE_CLIENT_ID", CasConfig.GoogleClientId);
                config.Require("REDIRECT_URI", CasConfig.RedirectUri());
                config.Require("ISSUER", CasConfig.Issuer);
                config.Require("AUDIENCE", CasConfig.Audience);
                config.Require("ALLOWED_ORIGINS", CasConfig.AllowedOrigins);
                config.Require("BASE_DOMAIN", CasConfig.BaseDomain());
                config.Require("PUBLIC_KEYS_URL", CasConfig.PublicKeysUrl);
                config.Require("PRIVATE_KEY", await config.PrivateKey(), hideValue: true);
                config.Require("PRIVATE_KEY_PASSWORD", await config.PrivateKeyPassword(), hideValue: true);
                config.Require("PUBLIC_CERT_0", await config.PublicCert(0), hideValue: true);
                config.Optional("PUBLIC_CERT_1", await config.PublicCert(1), hideValue: true, hideIfEmpty: true);
                config.Optional("PUBLIC_CERT_2", await config.PublicCert(2), hideValue: true, hideIfEmpty: true);
                config.Optional("PUBLIC_CERT_3", await config.PublicCert(3), hideValue: true, hideIfEmpty: true);
                config.Optional("DEFAULT_REDIRECT_URL", CasConfig.DefaultRedirectUrl);
                config.Optional("AZURE_APPLICATION_ID", CasConfig.AzureApplicationIds, hideIfEmpty: true);
                config.Optional("REQUIRE_SECURE_FOR_COOKIES", CasConfig.RequireSecureForCookies, hideValue: false);
                config.Optional("REQUIRE_USER_ENABLED_ON_REISSUE", CasConfig.RequireUserEnabledOnReissue, hideValue: false);
                config.Optional("REQUIRE_HTTPONLY_ON_USER_COOKIE", CasConfig.RequireHttpOnlyOnUserCookie, hideValue: false);
                config.Optional("REQUIRE_HTTPONLY_ON_XSRF_COOKIE", CasConfig.RequireHttpOnlyOnXsrfCookie, hideValue: false);
                config.Optional("VERIFY_XSRF_IN_HEADER", CasConfig.VerifyXsrfInHeader, hideValue: false);
                config.Optional("VERIFY_XSRF_IN_COOKIE", CasConfig.VerifyXsrfInCookie, hideValue: false);
                config.Optional("SAME_SITE", CasConfig.SameSite.ToString());
                config.Optional("USER_COOKIE_NAME", CasConfig.UserCookieName);
                config.Optional("ROLE_FOR_ADMIN", CasConfig.RoleForAdmin);
                config.Optional("ROLE_FOR_SERVICE", CasConfig.RoleForService);
                config.Optional("AZURE_DOMAIN_HINT", CasConfig.AzureDomainHint, hideIfEmpty: true);
                config.Optional("GOOGLE_DOMAIN_HINT", CasConfig.GoogleDomainHint, hideIfEmpty: true);
                config.Optional("GOOGLE_EMAIL_MUST_BE_VERIFIED", CasConfig.GoogleEmailMustBeVerified, hideValue: false);
                config.Optional("JWT_DURATION", CasConfig.JwtDuration.ToString());
                config.Optional("JWT_SERVICE_DURATION", CasConfig.JwtServiceDuration.ToString());
                config.Optional("JWT_MAX_DURATION", CasConfig.JwtMaxDuration.ToString());
                config.Optional("COMMAND_PASSWORD", await config.CommandPassword(), hideValue: true);
            }

            // add the issuer service
            services.AddSingleton <CasTokenIssuer, CasTokenIssuer>();

            // add the IDPs
            services.AddSingleton <ICasIdp, CasAzureAd>();
            if (!string.IsNullOrEmpty(CasConfig.GoogleClientId))
            {
                services.AddSingleton <ICasIdp, CasGoogleId>();
            }

            // setup CORS policy
            if (CasConfig.AllowedOrigins.Length > 0)
            {
                services.AddCors(options =>
                {
                    options.AddPolicy("cas-server", builder =>
                    {
                        builder.WithOrigins(CasConfig.AllowedOrigins)
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                    });
                });
            }
        }