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(); }
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); } } }; }
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(); }); }); } }