private async Task <bool> SendPayloadAsync(OpenIdConnectResponse response) { using (var buffer = new MemoryStream()) using (var writer = new JsonTextWriter(new StreamWriter(buffer))) { var serializer = JsonSerializer.CreateDefault(); serializer.Serialize(writer, response); writer.Flush(); // Note: when using basic authentication, returning an invalid_client error MUST result in // an unauthorized response but returning a 401 status code would invoke the previously // registered authentication middleware and potentially replace it by a 302 response. // To work around this OWIN/Katana limitation, a 400 response code is always returned. if (!string.IsNullOrEmpty(response.Error)) { Response.StatusCode = 400; } Response.ContentLength = buffer.Length; Response.ContentType = "application/json;charset=UTF-8"; switch (response.GetProperty <string>(OpenIdConnectConstants.Properties.MessageType)) { // Discovery, userinfo and introspection responses can be cached by the client // or the intermediate proxies. To allow the developer to set up his own response // caching policy, don't override the Cache-Control, Pragma and Expires headers. case OpenIdConnectConstants.MessageTypes.ConfigurationResponse: case OpenIdConnectConstants.MessageTypes.CryptographyResponse: case OpenIdConnectConstants.MessageTypes.IntrospectionResponse: case OpenIdConnectConstants.MessageTypes.UserinfoResponse: break; // Prevent the other responses from being cached. default: Response.Headers["Cache-Control"] = "no-cache"; Response.Headers["Pragma"] = "no-cache"; Response.Headers["Expires"] = "Thu, 01 Jan 1970 00:00:00 GMT"; break; } buffer.Seek(offset: 0, loc: SeekOrigin.Begin); await buffer.CopyToAsync(Response.Body, 4096, Request.CallCancelled); // Return true to stop processing the request. return(true); } }
private async Task <bool> SendPayloadAsync(OpenIdConnectResponse response) { using (var buffer = new MemoryStream()) using (var writer = new JsonTextWriter(new StreamWriter(buffer))) { var serializer = JsonSerializer.CreateDefault(); serializer.Serialize(writer, response); writer.Flush(); if (!string.IsNullOrEmpty(response.Error)) { Response.StatusCode = 400; } Response.ContentLength = buffer.Length; Response.ContentType = "application/json;charset=UTF-8"; switch (response.GetProperty <string>(OpenIdConnectConstants.Properties.MessageType)) { // Discovery, userinfo and introspection responses can be cached by the client // or the intermediate proxies. To allow the developer to set up his own response // caching policy, don't override the Cache-Control, Pragma and Expires headers. case OpenIdConnectConstants.MessageTypes.ConfigurationResponse: case OpenIdConnectConstants.MessageTypes.CryptographyResponse: case OpenIdConnectConstants.MessageTypes.IntrospectionResponse: case OpenIdConnectConstants.MessageTypes.UserinfoResponse: break; // Prevent the other responses from being cached. default: Response.Headers[HeaderNames.CacheControl] = "no-cache"; Response.Headers[HeaderNames.Pragma] = "no-cache"; Response.Headers[HeaderNames.Expires] = "-1"; break; } buffer.Seek(offset: 0, loc: SeekOrigin.Begin); await buffer.CopyToAsync(Response.Body, 4096, Context.RequestAborted); // Return true to stop processing the request. return(true); } }
private async Task <bool> SendPayloadAsync(OpenIdConnectResponse response) { using (var buffer = new MemoryStream()) using (var writer = new JsonTextWriter(new StreamWriter(buffer))) { var serializer = JsonSerializer.CreateDefault(); serializer.Serialize(writer, response); writer.Flush(); if (!string.IsNullOrEmpty(response.Error)) { // When client authentication is made using basic authentication, the authorization server MUST return // a 401 response with a valid WWW-Authenticate header containing the Basic scheme and a non-empty realm. // A similar error MAY be returned even when basic authentication is not used and MUST also be returned // when an invalid token is received by the userinfo endpoint using the Bearer authentication scheme. // To simplify the logic, a 401 response with the Bearer scheme is returned for invalid_token errors // and a 401 response with the Basic scheme is returned for invalid_client, even if the credentials // were specified in the request form instead of the HTTP headers, as allowed by the specification. string GetAuthenticationScheme() { switch (response.Error) { case OpenIdConnectConstants.Errors.InvalidClient: return(OpenIdConnectConstants.Schemes.Basic); case OpenIdConnectConstants.Errors.InvalidToken: return(OpenIdConnectConstants.Schemes.Bearer); default: return(null); } } var scheme = GetAuthenticationScheme(); if (!string.IsNullOrEmpty(scheme)) { Response.StatusCode = 401; Response.Headers[HeaderNames.WWWAuthenticate] = new StringBuilder() .Append(scheme) .Append(' ') .Append(OpenIdConnectConstants.Parameters.Realm) .Append("=\"") .Append(Context.GetIssuer(Options)) .Append('"') .ToString(); } else { Response.StatusCode = 400; } } Response.ContentLength = buffer.Length; Response.ContentType = "application/json;charset=UTF-8"; switch (response.GetProperty <string>(OpenIdConnectConstants.Properties.MessageType)) { // Discovery, userinfo and introspection responses can be cached by the client // or the intermediate proxies. To allow the developer to set up his own response // caching policy, don't override the Cache-Control, Pragma and Expires headers. case OpenIdConnectConstants.MessageTypes.ConfigurationResponse: case OpenIdConnectConstants.MessageTypes.CryptographyResponse: case OpenIdConnectConstants.MessageTypes.IntrospectionResponse: case OpenIdConnectConstants.MessageTypes.UserinfoResponse: break; // Prevent the other responses from being cached. default: Response.Headers[HeaderNames.CacheControl] = "no-cache"; Response.Headers[HeaderNames.Pragma] = "no-cache"; Response.Headers[HeaderNames.Expires] = "Thu, 01 Jan 1970 00:00:00 GMT"; break; } buffer.Seek(offset: 0, loc: SeekOrigin.Begin); await buffer.CopyToAsync(Response.Body, 4096, Context.RequestAborted); // Return true to stop processing the request. return(true); } }