1 package com.atlassian.asap.core.server.jersey; 2 3 import com.atlassian.asap.api.exception.AuthenticationFailedException; 4 import com.atlassian.asap.api.exception.AuthorizationFailedException; 5 import com.atlassian.asap.api.exception.PermanentAuthenticationFailedException; 6 import com.atlassian.asap.api.exception.TransientAuthenticationFailedException; 7 import com.atlassian.asap.core.JwtConstants; 8 9 import javax.ws.rs.container.ContainerRequestContext; 10 import javax.ws.rs.core.HttpHeaders; 11 import javax.ws.rs.core.Response; 12 13 import static java.lang.String.format; 14 15 /** 16 * An extension point for customizing how the authentication and authorization failures are returned to the client. 17 */ 18 @SuppressWarnings("WeakerAccess") 19 public interface FailureHandler { 20 /** 21 * Handles when the Jwt token cannot validated, because of a possibly transient error (like a communication 22 * failure or 500 error response). In this case a retry maybe possible. 23 * 24 * <p>Iif no retry is to be attempted (returning {@code false}, then the request should be aborted using the 25 * {@link ContainerRequestContext} instance. 26 * 27 * <p>By default, this method simply delegate to 28 * {@link #onAuthenticationFailure(ContainerRequestContext, AuthenticationFailedException)} and returns 29 * {@code false} in order to NOT retry. 30 * 31 * @param context The request context 32 * @param e The {@link TransientAuthenticationFailedException} 33 * @return {@code true} if the authentication should be retried, {@code false} otherwise. 34 * @see #onPermanentAuthenticationFailure(ContainerRequestContext, PermanentAuthenticationFailedException) 35 * @see #onAuthenticationFailure(ContainerRequestContext, AuthenticationFailedException) 36 * @since 2.9.0 37 */ 38 default boolean onTransientAuthenticationFailure(ContainerRequestContext context, 39 TransientAuthenticationFailedException e) { 40 onAuthenticationFailure(context, e); 41 return false; // do not retry by default 42 } 43 44 /** 45 * Handles when the Jwt token cannot validated, because of a permanent error (such as wrong header value, 46 * incorrect signature, etc.). Requests should be aborted using the {@link ContainerRequestContext} instance. 47 * 48 * <p>By default, this method simply delegate to 49 * {@link #onAuthenticationFailure(ContainerRequestContext, AuthenticationFailedException)} 50 * 51 * @param context The request context 52 * @param e The {@link PermanentAuthenticationFailedException} 53 * @see #onTransientAuthenticationFailure(ContainerRequestContext, TransientAuthenticationFailedException) 54 * @see #onAuthenticationFailure(ContainerRequestContext, AuthenticationFailedException) 55 * @since 2.9.0 56 */ 57 default void onPermanentAuthenticationFailure(ContainerRequestContext context, 58 PermanentAuthenticationFailedException e) { 59 onAuthenticationFailure(context, e); 60 } 61 62 /** 63 * Handles when the Jwt token cannot be parsed or validated. Requests should be aborted using the {@link 64 * ContainerRequestContext} instance 65 * 66 * <p>Default implementation returns a {@link Response.Status#UNAUTHORIZED HTTP 401} with an empty body. 67 * 68 * <p>If you want to handle more sprecific {@link TransientAuthenticationFailedException} 69 * and {@link PermanentAuthenticationFailedException}, respectively implement 70 * {@link #onTransientAuthenticationFailure(ContainerRequestContext, TransientAuthenticationFailedException)} 71 * and {@link #onPermanentAuthenticationFailure(ContainerRequestContext, PermanentAuthenticationFailedException)}. 72 * <strong>Note</strong> you'll still need to implement this method to handle generic 73 * {@link AuthenticationFailedException}s. 74 * 75 * @param context The request context 76 * @param e The {@link AuthenticationFailedException} 77 * @since 2.9.0 78 */ 79 default void onAuthenticationFailure(ContainerRequestContext context, AuthenticationFailedException e) { 80 onAuthenticationFailure(context, format("JWT token cannot be verified: %s", e.getMessage())); 81 } 82 83 /** 84 * Handles when the Jwt token cannot be parsed or validated. Requests should be aborted using the {@link 85 * ContainerRequestContext} instance 86 * 87 * @param context The request context 88 * @param message The error message 89 * @since 2.9.0. 90 * @deprecated Use {@link #onAuthenticationFailure(ContainerRequestContext, AuthenticationFailedException)} instead. 91 */ 92 @Deprecated 93 default void onAuthenticationFailure(ContainerRequestContext context, String message) { 94 context.abortWith(Response.status(Response.Status.UNAUTHORIZED) 95 .header(HttpHeaders.WWW_AUTHENTICATE, JwtConstants.BEARER_AUTHENTICATION_SCHEME) 96 .build()); 97 } 98 99 /** 100 * Handles when the Jwt token claims cannot be authorized. Requests should be aborted using the {@link 101 * ContainerRequestContext} instance 102 * 103 * @param context The request context 104 * @param e The {@link AuthorizationFailedException authorization exception} 105 * @since 2.9.0 106 */ 107 default void onAuthorizationFailure(ContainerRequestContext context, AuthorizationFailedException e) { 108 onAuthorizationFailure(context, e.getMessage()); 109 } 110 111 /** 112 * Handles when the Jwt token claims cannot be authorized. Requests should be aborted using the {@link 113 * ContainerRequestContext} instance 114 * 115 * @param context The request context 116 * @param message The error message 117 * @since v2.9.0. 118 * @deprecated Use {@link #onAuthorizationFailure(ContainerRequestContext, AuthorizationFailedException)} instead. 119 */ 120 @Deprecated 121 default void onAuthorizationFailure(ContainerRequestContext context, String message) { 122 context.abortWith(Response.status(Response.Status.FORBIDDEN).build()); 123 } 124 }