private async Task <bool> SendUserinfoResponseAsync(OpenIdConnectResponse response) { var request = Context.GetOpenIdConnectRequest(); if (request == null) { request = new OpenIdConnectRequest(); } Context.SetOpenIdConnectResponse(response); var notification = new ApplyUserinfoResponseContext(Context, Options, request, response); await Options.Provider.ApplyUserinfoResponse(notification); if (notification.HandledResponse) { return(true); } else if (notification.Skipped) { return(false); } return(await SendPayloadAsync(response)); }
private async Task <bool> HandleLogoutAsync(AuthenticationResponseRevoke context) { // Extract the OpenID Connect request from the OWIN/Katana context. // If it cannot be found or doesn't correspond to a logout request, // throw an InvalidOperationException. var request = Context.GetOpenIdConnectRequest(); if (request == null || !request.IsLogoutRequest()) { throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } // Note: if an OpenID Connect response was already generated, throw an exception. var response = Context.GetOpenIdConnectResponse(); if (response != null) { throw new InvalidOperationException("An OpenID Connect response has already been sent."); } // Prepare a new a OpenID Connect response. response = new OpenIdConnectResponse { PostLogoutRedirectUri = request.GetProperty <string>(OpenIdConnectConstants.Properties.PostLogoutRedirectUri), State = request.State }; return(await SendLogoutResponseAsync(response)); }
protected override Task HandleSignOutAsync(SignOutContext context) { // Extract the OpenID Connect request from the ASP.NET context. // If it cannot be found or doesn't correspond to a logout request, // throw an InvalidOperationException. var request = Context.GetOpenIdConnectRequest(); if (request == null || !request.IsLogoutRequest()) { throw new InvalidOperationException("An OpenID Connect response cannot be returned from this endpoint."); } // Note: if an OpenID Connect response was already generated, throw an exception. var response = Context.GetOpenIdConnectResponse(); if (response != null) { throw new InvalidOperationException("An OpenID Connect response has already been sent."); } // Prepare a new OpenID Connect response. response = new OpenIdConnectResponse { PostLogoutRedirectUri = request.PostLogoutRedirectUri, State = request.State }; return(SendLogoutResponseAsync(response)); }
private async Task <bool> HandleChallengeAsync(AuthenticationResponseChallenge context) { // Extract the OpenID Connect request from the OWIN/Katana context. // If it cannot be found or doesn't correspond to an authorization // or a token request, throw an InvalidOperationException. var request = Context.GetOpenIdConnectRequest(); if (request == null || (!request.IsAuthorizationRequest() && !request.IsTokenRequest())) { throw new InvalidOperationException("An authorization or token response cannot be returned from this endpoint."); } // Note: if a response was already generated, throw an exception. var response = Context.GetOpenIdConnectResponse(); if (response != null) { throw new InvalidOperationException("A response has already been sent."); } // Create a new ticket containing an empty identity and // the authentication properties extracted from the challenge. var ticket = new AuthenticationTicket(new ClaimsIdentity(), context.Properties); // Prepare a new OpenID Connect response. response = new OpenIdConnectResponse { Error = ticket.GetProperty(OpenIdConnectConstants.Properties.Error), ErrorDescription = ticket.GetProperty(OpenIdConnectConstants.Properties.ErrorDescription), ErrorUri = ticket.GetProperty(OpenIdConnectConstants.Properties.ErrorUri) }; // Remove the error/error_description/error_uri properties from the ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.Error) .RemoveProperty(OpenIdConnectConstants.Properties.ErrorDescription) .RemoveProperty(OpenIdConnectConstants.Properties.ErrorUri); if (string.IsNullOrEmpty(response.Error)) { response.Error = request.IsAuthorizationRequest() ? OpenIdConnectConstants.Errors.AccessDenied : OpenIdConnectConstants.Errors.InvalidGrant; } if (string.IsNullOrEmpty(response.ErrorDescription)) { response.ErrorDescription = request.IsAuthorizationRequest() ? "The authorization was denied by the resource owner." : "The token request was rejected by the authorization server."; } Logger.LogTrace("A challenge operation was triggered: {Properties}.", context.Properties.Dictionary); if (request.IsAuthorizationRequest()) { return(await SendAuthorizationResponseAsync(response, ticket)); } return(await SendTokenResponseAsync(response, ticket)); }
private async Task <bool> SendTokenResponseAsync(OpenIdConnectResponse response, AuthenticationTicket ticket = null) { var request = Context.GetOpenIdConnectRequest(); Context.SetOpenIdConnectResponse(response); response.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.TokenResponse); var notification = new ApplyTokenResponseContext(Context, Scheme, Options, ticket, request, response); await Provider.ApplyTokenResponse(notification); if (notification.Result != null) { if (notification.Result.Handled) { Logger.LogDebug("The token request was handled in user code."); return(true); } else if (notification.Result.Skipped) { Logger.LogDebug("The default token request handling was skipped from user code."); return(false); } } Logger.LogInformation("The token response was successfully returned: {Response}.", response); return(await SendPayloadAsync(response)); }
private async Task <bool> SendRevocationResponseAsync(OpenIdConnectResponse response) { var request = Context.GetOpenIdConnectRequest(); Context.SetOpenIdConnectResponse(response); response.SetProperty(OpenIdConnectConstants.Properties.MessageType, OpenIdConnectConstants.MessageTypes.RevocationResponse); var notification = new ApplyRevocationResponseContext(Context, Options, request, response); await Options.Provider.ApplyRevocationResponse(notification); if (notification.HandledResponse) { Logger.LogDebug("The revocation request was handled in user code."); return(true); } else if (notification.Skipped) { Logger.LogDebug("The default revocation request handling was skipped from user code."); return(false); } Logger.LogInformation("The revocation response was successfully returned: {Response}.", response); return(await SendPayloadAsync(response)); }
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"; Response.Headers[HeaderNames.CacheControl] = "no-cache"; Response.Headers[HeaderNames.Pragma] = "no-cache"; Response.Headers[HeaderNames.Expires] = "-1"; buffer.Seek(offset: 0, loc: SeekOrigin.Begin); await buffer.CopyToAsync(Response.Body, 4096, Context.RequestAborted); // Return true to stop processing the request. return(true); } }
public async Task BindModelAsync_ReturnsAmbientResponse() { // Arrange var binder = new OpenIddictModelBinder(); var provider = new EmptyModelMetadataProvider(); var response = new OpenIdConnectResponse(); var features = new FeatureCollection(); features.Set(new OpenIdConnectServerFeature { Response = response }); var context = new DefaultModelBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(features), }, ModelMetadata = provider.GetMetadataForType(typeof(OpenIdConnectResponse)), ValidationState = new ValidationStateDictionary() }; // Act await binder.BindModelAsync(context); // Assert Assert.True(context.Result.IsModelSet); Assert.Same(response, context.Result.Model); Assert.True(context.ValidationState[response].SuppressValidation); }
public IdentityException(string error, string message) : base(message) { Response = new OpenIdConnectResponse { Error = error, ErrorDescription = message }; }
private async Task <bool> HandleLogoutAsync(AuthenticationProperties properties) { // Extract the OpenID Connect request from the OWIN/Katana context. // If it cannot be found or doesn't correspond to a logout request, // throw an InvalidOperationException. var request = Context.GetOpenIdConnectRequest(); if (request == null || !request.IsLogoutRequest()) { throw new InvalidOperationException("A logout response cannot be returned from this endpoint."); } // Note: if a response was already generated, throw an exception. var response = Context.GetOpenIdConnectResponse(); if (response != null) { throw new InvalidOperationException("A response has already been sent."); } Logger.LogTrace("A log-out operation was triggered: {Properties}.", properties.Dictionary); // Prepare a new OpenID Connect response. response = new OpenIdConnectResponse(); var notification = new ProcessSignoutResponseContext(Context, Options, properties, request, response); await Options.Provider.ProcessSignoutResponse(notification); if (notification.HandledResponse) { Logger.LogDebug("The sign-out response was handled in user code."); return(true); } else if (notification.Skipped) { Logger.LogDebug("The default sign-out handling was skipped from user code."); return(false); } else if (notification.IsRejected) { Logger.LogError("The request was rejected with the following error: {Error} ; {Description}", /* Error: */ notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, /* Description: */ notification.ErrorDescription); return(await SendLogoutResponseAsync(new OpenIdConnectResponse { Error = notification.Error ?? OpenIdConnectConstants.Errors.InvalidRequest, ErrorDescription = notification.ErrorDescription, ErrorUri = notification.ErrorUri })); } return(await SendLogoutResponseAsync(response)); }
private async Task <string> SerializeRefreshTokenAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in refresh tokens are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(principal, properties, Scheme.Name); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; // Only set the expiration date if a lifetime was specified in either the ticket or the options. var lifetime = ticket.GetRefreshTokenLifetime() ?? Options.RefreshTokenLifetime; if (lifetime.HasValue) { ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + lifetime.Value; } // Associate a random identifier with the refresh token. ticket.SetTokenId(Guid.NewGuid().ToString()); // Remove the unwanted properties from the authentication ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime) .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallenge) .RemoveProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod) .RemoveProperty(OpenIdConnectConstants.Properties.Nonce) .RemoveProperty(OpenIdConnectConstants.Properties.OriginalRedirectUri) .RemoveProperty(OpenIdConnectConstants.Properties.TokenUsage); var notification = new SerializeRefreshTokenContext(Context, Scheme, Options, request, response, ticket) { DataFormat = Options.RefreshTokenFormat }; await Provider.SerializeRefreshToken(notification); if (notification.IsHandled || !string.IsNullOrEmpty(notification.RefreshToken)) { return(notification.RefreshToken); } if (notification.DataFormat == null) { throw new InvalidOperationException("A data formatter must be provided."); } var result = notification.DataFormat.Protect(ticket); Logger.LogTrace("A new refresh token was successfully generated using the " + "specified data format: {Token} ; {Claims} ; {Properties}.", result, ticket.Principal.Claims, ticket.Properties.Items); return(result); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsIdentity identity, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // properties.IssuedUtc and properties.ExpiresUtc // should always be preferred when explicitly set. if (properties.IssuedUtc == null) { properties.IssuedUtc = Options.SystemClock.UtcNow; } if (properties.ExpiresUtc == null) { properties.ExpiresUtc = properties.IssuedUtc + Options.AuthorizationCodeLifetime; } // Claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. var ticket = new AuthenticationTicket(identity, properties); ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode); // Associate a random identifier with the authorization code. ticket.SetTicketId(Guid.NewGuid().ToString()); // By default, add the client_id to the list of the // presenters allowed to use the authorization code. if (!string.IsNullOrEmpty(request.ClientId)) { ticket.SetPresenters(request.ClientId); } var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } if (notification.DataFormat == null) { return(null); } return(notification.DataFormat.Protect(ticket)); }
public string Error(OpenIdConnectResponse response) { if (response == null) { return("error"); } Logger.LogError(JsonHelper.ToJson(response)); return(JsonHelper.ToJson(response)); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsIdentity identity, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(identity, properties); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + (ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime); ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode); // Associate a random identifier with the authorization code. ticket.SetTicketId(Guid.NewGuid().ToString()); // Store the code_challenge, code_challenge_method and nonce parameters for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallenge, request.CodeChallenge) .SetProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod, request.CodeChallengeMethod) .SetProperty(OpenIdConnectConstants.Properties.Nonce, request.Nonce); // Store the original redirect_uri sent by the client application for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.RedirectUri, request.GetProperty <string>(OpenIdConnectConstants.Properties.OriginalRedirectUri)); // Remove the unwanted properties from the authentication ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime) .RemoveProperty(OpenIdConnectConstants.Properties.ClientId); var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } if (notification.DataFormat == null) { return(null); } return(notification.DataFormat.Protect(ticket)); }
/// <summary> /// Creates a new instance of the <see cref="SerializeAccessTokenContext"/> class. /// </summary> public SerializeAccessTokenContext( IOwinContext context, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response, AuthenticationTicket ticket) : base(context, options, request, response, ticket) { }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsIdentity identity, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(identity, properties); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc; ticket.Properties.ExpiresUtc += ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime; // Associate a random identifier with the authorization code. ticket.SetTokenId(Guid.NewGuid().ToString()); // Store the code_challenge, code_challenge_method and nonce parameters for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.CodeChallenge, request.CodeChallenge) .SetProperty(OpenIdConnectConstants.Properties.CodeChallengeMethod, request.CodeChallengeMethod) .SetProperty(OpenIdConnectConstants.Properties.Nonce, request.Nonce); // Store the original redirect_uri sent by the client application for later comparison. ticket.SetProperty(OpenIdConnectConstants.Properties.OriginalRedirectUri, request.GetProperty <string>(OpenIdConnectConstants.Properties.OriginalRedirectUri)); // Remove the unwanted properties from the authentication ticket. ticket.RemoveProperty(OpenIdConnectConstants.Properties.AuthorizationCodeLifetime) .RemoveProperty(OpenIdConnectConstants.Properties.TokenUsage); var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.IsHandled || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } if (notification.DataFormat == null) { throw new InvalidOperationException("A data formatter must be provided."); } var result = notification.DataFormat.Protect(ticket); Logger.LogTrace("A new authorization code was successfully generated using " + "the specified data format: {Code} ; {Claims} ; {Properties}.", result, ticket.Identity.Claims, ticket.Properties.Dictionary); return(result); }
private async Task <string> SerializeAuthorizationCodeAsync( ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) { // Note: claims in authorization codes are never filtered as they are supposed to be opaque: // SerializeAccessTokenAsync and SerializeIdentityTokenAsync are responsible of ensuring // that subsequent access and identity tokens are correctly filtered. // Create a new ticket containing the updated properties. var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme); ticket.Properties.IssuedUtc = Options.SystemClock.UtcNow; ticket.Properties.ExpiresUtc = ticket.Properties.IssuedUtc + (ticket.GetAuthorizationCodeLifetime() ?? Options.AuthorizationCodeLifetime); ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode); // Associate a random identifier with the authorization code. ticket.SetTicketId(Guid.NewGuid().ToString()); // By default, add the client_id to the list of the // presenters allowed to use the authorization code. if (!string.IsNullOrEmpty(request.ClientId)) { ticket.SetPresenters(request.ClientId); } var notification = new SerializeAuthorizationCodeContext(Context, Options, request, response, ticket) { DataFormat = Options.AuthorizationCodeFormat }; await Options.Provider.SerializeAuthorizationCode(notification); if (notification.HandledResponse || !string.IsNullOrEmpty(notification.AuthorizationCode)) { return(notification.AuthorizationCode); } else if (notification.Skipped) { return(null); } if (!ReferenceEquals(ticket, notification.Ticket)) { throw new InvalidOperationException("The authentication ticket cannot be replaced."); } if (notification.DataFormat == null) { return(null); } return(notification.DataFormat.Protect(ticket)); }
/// <summary> /// Creates an instance of this context. /// </summary> public ApplyConfigurationResponseContext( IOwinContext context, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context, options) { Request = request; Response = response; }
/// <summary> /// Creates a new instance of the <see cref="SerializeAuthorizationCodeContext"/> class. /// </summary> public SerializeAuthorizationCodeContext( HttpContext context, AuthenticationScheme scheme, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response, AuthenticationTicket ticket) : base(context, scheme, options, request, response, ticket) { }
public void PropertyGetter_ReturnsExpectedParameter(string property, string name, OpenIdConnectParameter value) { // Arrange var response = new OpenIdConnectResponse(); response.SetParameter(name, value); // Act and assert Assert.Equal(value.Value, typeof(OpenIdConnectResponse).GetProperty(property).GetValue(response)); }
public void PropertySetter_AddsExpectedParameter(string property, string name, object value) { // Arrange var response = new OpenIdConnectResponse(); // Act typeof(OpenIdConnectResponse).GetProperty(property).SetValue(response, value); // Assert Assert.Equal(JToken.FromObject(value), response.GetParameter(name)); }
public void GetOpenIdConnectResponse_ReturnsExpectedResponse() { // Arrange var response = new OpenIdConnectResponse(); var context = new OwinContext(); context.Set(typeof(OpenIdConnectResponse).FullName, response); // Act and assert Assert.Same(response, context.GetOpenIdConnectResponse()); }
private IActionResult RedirectToClient(OpenIdConnectResponse response) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictConstants.Properties.Error] = response.Error, [OpenIddictConstants.Properties.ErrorDescription] = response.ErrorDescription, [OpenIddictConstants.Properties.ErrorUri] = response.ErrorUri, }); return(Forbid(properties, OpenIddictServerDefaults.AuthenticationScheme)); }
/// <summary> /// Initializes a new instance of the <see cref="ApplyLogoutResponseContext"/> class /// </summary> /// <param name="context"></param> /// <param name="options"></param> /// <param name="request"></param> /// <param name="response"></param> public ApplyLogoutResponseContext( HttpContext context, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context) { Options = options; Request = request; Response = response; }
/// <summary> /// Creates a new instance of the <see cref="ProcessSigninResponseContext"/> class. /// </summary> public ProcessSigninResponseContext( IOwinContext context, OpenIdConnectServerOptions options, AuthenticationTicket ticket, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context, options, request, ticket) { Validate(); Response = response; }
/// <summary> /// Creates a new instance of the <see cref="ApplyLogoutResponseContext"/> class. /// </summary> public ApplyLogoutResponseContext( HttpContext context, AuthenticationScheme scheme, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context, scheme, options) { Request = request; Response = response; }
/// <summary> /// Creates a new instance of the <see cref="ProcessSignoutResponseContext"/> class. /// </summary> public ProcessSignoutResponseContext( IOwinContext context, OpenIdConnectServerOptions options, AuthenticationProperties properties, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context, options, request) { Validate(); Properties = properties; Response = response; }
public void SetOpenIdConnectResponse_AttachesResponse() { // Arrange var response = new OpenIdConnectResponse(); var context = new OwinContext(); // Act context.SetOpenIdConnectResponse(response); // Assert Assert.Same(response, context.Get <OpenIdConnectResponse>(typeof(OpenIdConnectResponse).FullName)); }
/// <summary> /// Initializes a new instance of the <see cref="SerializeRefreshTokenContext"/> class /// </summary> /// <param name="context"></param> /// <param name="options"></param> /// <param name="request"></param> /// <param name="response"></param> /// <param name="ticket"></param> public SerializeRefreshTokenContext( IOwinContext context, OpenIdConnectServerOptions options, OpenIdConnectRequest request, OpenIdConnectResponse response, AuthenticationTicket ticket) : base(context, options) { Request = request; Response = response; Ticket = ticket; }
/// <summary> /// Initializes a new instance of the <see cref="ApplyAuthorizationResponseContext"/> class /// </summary> /// <param name="context"></param> /// <param name="options"></param> /// <param name="ticket"></param> /// <param name="request"></param> /// <param name="response"></param> public ApplyAuthorizationResponseContext( IOwinContext context, OpenIdConnectServerOptions options, AuthenticationTicket ticket, OpenIdConnectRequest request, OpenIdConnectResponse response) : base(context, options) { Ticket = ticket; Request = request; Response = response; }