Esempio n. 1
0
        /*
         * private async Task<Tokens> GetAccessTokenFromAuthCode(HttpClient httpClient, HttpContext context, ICasConfig config, string code, string scope)
         * {
         *
         *  // get the client secret
         *  var secret = await config.GetString("CLIENT_SECRET", CasEnv.AzureClientSecret);
         *
         *  // get the response
         *  using (var request = new HttpRequestMessage()
         *  {
         *      RequestUri = new Uri($"{CasEnv.AzureAuthority}/oauth2/v2.0/token"),
         *      Method = HttpMethod.Post
         *  })
         *  {
         *      using (request.Content = new FormUrlEncodedContent(new[] {
         *          new KeyValuePair<string, string>("client_id", CasEnv.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", CasEnv.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;
         *          }
         *      }
         *  };
         *
         * }
         *
         * private async Task<Tokens> GetAccessTokenFromRefreshToken(HttpClient httpClient, ICasConfig config, string refreshToken, string scope)
         * {
         *
         *  // get the client secret
         *  var secret = await config.GetString("CLIENT_SECRET", CasEnv.AzureClientSecret);
         *
         *  // get the response
         *  using (var request = new HttpRequestMessage()
         *  {
         *      RequestUri = new Uri($"{CasEnv.AzureAuthority}/oauth2/v2.0/token"),
         *      Method = HttpMethod.Post
         *  })
         *  {
         *      using (request.Content = new FormUrlEncodedContent(new[] {
         *          new KeyValuePair<string, string>("client_id", CasEnv.AzureClientId),
         *          new KeyValuePair<string, string>("client_secret", secret),
         *          new KeyValuePair<string, string>("scope", scope),
         *          new KeyValuePair<string, string>("refresh_token", refreshToken),
         *          new KeyValuePair<string, string>("grant_type", "refresh_token")
         *      }))
         *      {
         *          using (var response = await httpClient.SendAsync(request))
         *          {
         *              var raw = await response.Content.ReadAsStringAsync();
         *              if (!response.IsSuccessStatusCode)
         *              {
         *                  throw new Exception($"GetAccessTokenFromRefreshToken: HTTP {(int)response.StatusCode} - {raw}");
         *              }
         *              var tokens = JsonConvert.DeserializeObject<Tokens>(raw);
         *              return tokens;
         *          }
         *      }
         *  };
         *
         * }
         *
         * private async Task<Tokens> GetAccessTokenFromClientSecret(HttpClient httpClient, string clientId, string clientSecret, string scope)
         * {
         *
         *  // get the response
         *  using (var request = new HttpRequestMessage()
         *  {
         *      RequestUri = new Uri($"{CasEnv.AzureAuthority}/oauth2/v2.0/token"),
         *      Method = HttpMethod.Post
         *  })
         *  {
         *      using (request.Content = new FormUrlEncodedContent(new[] {
         *          new KeyValuePair<string, string>("client_id", clientId),
         *          new KeyValuePair<string, string>("client_secret", clientSecret),
         *          new KeyValuePair<string, string>("scope", scope),
         *          new KeyValuePair<string, string>("grant_type", "client_credentials")
         *      }))
         *      {
         *          using (var response = await httpClient.SendAsync(request))
         *          {
         *              var raw = await response.Content.ReadAsStringAsync();
         *              if (!response.IsSuccessStatusCode)
         *              {
         *                  throw new Exception($"GetAccessTokenFromClientSecret: HTTP {(int)response.StatusCode} - {raw}");
         *              }
         *              var tokens = JsonConvert.DeserializeObject<Tokens>(raw);
         *              return tokens;
         *          }
         *      }
         *  };
         *
         * }
         *
         * private async Task<Tokens> GetAccessTokenFromClientCertificate(HttpClient httpClient, string clientId, string token, string scope)
         * {
         *
         *  // get the response
         *  using (var request = new HttpRequestMessage()
         *  {
         *      RequestUri = new Uri($"{CasEnv.AzureAuthority}/oauth2/v2.0/token"),
         *      Method = HttpMethod.Post
         *  })
         *  {
         *      using (request.Content = new FormUrlEncodedContent(new[] {
         *          new KeyValuePair<string, string>("client_id", clientId),
         *          new KeyValuePair<string, string>("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"),
         *          new KeyValuePair<string, string>("client_assertion", token),
         *          new KeyValuePair<string, string>("scope", scope),
         *          new KeyValuePair<string, string>("grant_type", "client_credentials")
         *      }))
         *      {
         *          using (var response = await httpClient.SendAsync(request))
         *          {
         *              var raw = await response.Content.ReadAsStringAsync();
         *              if (!response.IsSuccessStatusCode)
         *              {
         *                  throw new Exception($"GetAccessTokenFromClientSecret: HTTP {(int)response.StatusCode} - {raw}");
         *              }
         *              var tokens = JsonConvert.DeserializeObject<Tokens>(raw);
         *              return tokens;
         *          }
         *      }
         *  };
         *
         * }
         */

        public override async Task Token(HttpContext context)
        {
            // get the authflow
            if (!context.Request.Cookies.ContainsKey("authflow"))
            {
                throw new CasHttpException(400, "authflow not provided");
            }
            var flow = JsonConvert.DeserializeObject <CasAuthFlow>(context.Request.Cookies["authflow"]);

            if (context.Request.Form["state"] != flow.state)
            {
                throw new CasHttpException(400, "state does not match");
            }

            // NOTE: google seems to throw errors on their own domain, they don't return them

            // verify the id_token
            string idRaw   = context.Request.Form["id_token"];
            var    idToken = await VerifyTokenFromGoogle(idRaw, CasConfig.GoogleClientId, flow.nonce);

            // ensure the email is verified
            if (CasConfig.GoogleEmailMustBeVerified)
            {
                var verified = idToken.Payload.Claims.FirstOrDefault(c => c.Type == "email_verified");
                if (verified.Value != "true")
                {
                    throw new CasHttpException(403, "email was not verified");
                }
            }

            // ICasAuthCodeReceiver: use the code to get an access token

            /* NOTE: I have not tested authcode with google yet
             * var authCodeReceiver = context.RequestServices.GetService<ICasAuthCodeReceiver>();
             * if (authCodeReceiver != null)
             * {
             *  string code = context.Request.Query["code"];
             *  Tokens last = null;
             *  var scopes = await authCodeReceiver.GetAllScopes();
             *  foreach (var scope in scopes)
             *  {
             *      if (last == null)
             *      {
             *          last = await GetAccessTokenFromAuthCode(httpClient, context, config, code, "offline_access " + scope);
             *      }
             *      else
             *      {
             *          last = await GetAccessTokenFromRefreshToken(httpClient, config, last.refresh_token, "offline_access " + scope);
             *      }
             *      await authCodeReceiver.ReceiveAll(scope, last.access_token, last.refresh_token);
             *      break;
             *  }
             * }
             */

            // build the claims
            var claims = BuildClaims(idToken);

            // add a sub (useful for istio)
            var sub =
                claims.FirstOrDefault(c => c.Type == "email") ??
                idToken.Payload.Claims.FirstOrDefault(c => c.Type == "sub");

            if (sub != null)
            {
                claims.Add(new Claim("sub", sub.Value));
            }

            // NOTE: google does not have an oid equivalent
            // NOTE: google does not support role claims

            // apply custom claims
            if (ClaimsBuilder != null)
            {
                await ClaimsBuilder.AddAllClaims(idToken.Payload.Claims, claims);
            }

            // write the token cookies
            await WriteTokenCookies(context, claims);

            // redirect
            await Redirect(context, flow);
        }
Esempio n. 2
0
        public override async Task Token(HttpContext context)
        {
            // read flow, verify state and nonce
            if (!context.Request.Cookies.ContainsKey("authflow"))
            {
                throw new CasHttpException(400, "authflow not provided");
            }
            var flow = JsonConvert.DeserializeObject <CasAuthFlow>(context.Request.Cookies["authflow"]);

            if (context.Request.Form["state"] != flow.state)
            {
                throw new CasHttpException(400, "state does not match");
            }

            // throw error if one was returned
            if (context.Request.Form.ContainsKey("error_description"))
            {
                throw new CasHttpException(401, context.Request.Form["error_description"]);
            }

            // verify the id token
            string idRaw   = context.Request.Form["id_token"];
            var    idToken = await VerifyTokenFromAAD(idRaw, CasConfig.AzureClientId, flow.nonce);

            // ICasAuthCodeReceiver: use the code to get an access token
            if (AuthCodeReceiver != null)
            {
                // get code
                string code = context.Request.Form["code"];
                Tokens last = null;

                // get tokens for each scope
                var scopes = await AuthCodeReceiver.GetAllScopes();

                foreach (var scope in scopes)
                {
                    if (last == null)
                    {
                        last = await GetAccessTokenFromAuthCode(context, code, "offline_access " + scope);
                    }
                    else
                    {
                        last = await GetAccessTokenFromRefreshToken(last.refresh_token, "offline_access " + scope);
                    }
                    await AuthCodeReceiver.ReceiveAll(scope, last.access_token, last.refresh_token);

                    break;
                }
            }

            // populate the claims from the id_token
            var claims = BuildClaims(idToken);

            // get the oid
            var oid = await GetOid(idToken, claims);

            // add a sub (useful for istio)
            var sub =
                claims.FirstOrDefault(c => c.Type == "email") ??
                claims.FirstOrDefault(c => c.Type == "oid") ??
                idToken.Payload.Claims.FirstOrDefault(c => c.Type == "sub");

            if (sub != null)
            {
                claims.Add(new Claim("sub", sub.Value));
            }

            // attempt to propogate roles
            var roles = idToken.Payload.Claims.Where(c => c.Type == "roles");

            foreach (var role in roles)
            {
                claims.Add(new Claim("role", role.Value));
            }

            // populate all application roles from the graph
            if (oid != null)
            {
                var assignments = await GetRoleAssignments(oid);

                foreach (var assignment in assignments)
                {
                    foreach (var role in assignment.Roles)
                    {
                        claims.Add(new Claim(assignment.AppId + "-role", role));
                    }
                }
            }

            // apply custom claims
            if (ClaimsBuilder != null)
            {
                await ClaimsBuilder.AddAllClaims(idToken.Payload.Claims, claims);
            }

            // wrote the cookies
            await WriteTokenCookies(context, claims);

            // redirect
            await Redirect(context, flow);
        }