| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.fineract.infrastructure.security.service; |
| |
| import jakarta.servlet.ServletException; |
| import jakarta.servlet.http.HttpServletRequest; |
| import jakarta.servlet.http.HttpServletResponse; |
| import jakarta.servlet.http.HttpSession; |
| import java.io.IOException; |
| import lombok.extern.slf4j.Slf4j; |
| import org.springframework.security.core.AuthenticationException; |
| import org.springframework.security.web.DefaultRedirectStrategy; |
| import org.springframework.security.web.RedirectStrategy; |
| import org.springframework.security.web.WebAttributes; |
| import org.springframework.security.web.authentication.AuthenticationFailureHandler; |
| import org.springframework.security.web.util.UrlUtils; |
| import org.springframework.util.Assert; |
| |
| @Slf4j |
| public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { |
| |
| private String defaultFailureUrl; |
| private boolean forwardToDestination = false; |
| private boolean allowSessionCreation = true; |
| private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); |
| |
| public CustomAuthenticationFailureHandler() {} |
| |
| /** |
| * Performs the redirect or forward to the {@code defaultFailureUrl} if set, otherwise returns a 401 error code. |
| * <p> |
| * If redirecting or forwarding, {@code saveException} will be called to cache the exception for use in the target |
| * view. |
| */ |
| @Override |
| public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response, |
| final AuthenticationException exception) throws IOException, ServletException { |
| |
| if (this.defaultFailureUrl == null) { |
| log.debug("No failure URL set, sending 401 Unauthorized error"); |
| |
| response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage()); |
| } else { |
| saveException(request, exception); |
| |
| if (this.forwardToDestination) { |
| log.debug("Forwarding to {}", this.defaultFailureUrl); |
| |
| request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response); |
| } else { |
| log.debug("Redirecting to {}", this.defaultFailureUrl); |
| |
| final String oauthToken = request.getParameter("oauth_token"); |
| request.setAttribute("oauth_token", oauthToken); |
| final String url = this.defaultFailureUrl + "?oauth_token=" + oauthToken; |
| this.redirectStrategy.sendRedirect(request, response, url); |
| } |
| } |
| } |
| |
| /** |
| * Caches the {@code AuthenticationException} for use in view rendering. |
| * <p> |
| * If {@code forwardToDestination} is set to true, request scope will be used, otherwise it will attempt to store |
| * the exception in the session. If there is no session and {@code allowSessionCreation} is {@code true} a session |
| * will be created. Otherwise the exception will not be stored. |
| */ |
| protected final void saveException(final HttpServletRequest request, final AuthenticationException exception) { |
| if (this.forwardToDestination) { |
| request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); |
| } else { |
| final HttpSession session = request.getSession(false); |
| |
| if (session != null || this.allowSessionCreation) { |
| request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception); |
| } |
| } |
| } |
| |
| /** |
| * The URL which will be used as the failure destination. |
| * |
| * @param defaultFailureUrl |
| * the failure URL, for example "/loginFailed.jsp". |
| */ |
| public void setDefaultFailureUrl(final String defaultFailureUrl) { |
| Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl), "'" + defaultFailureUrl + "' is not a valid redirect URL"); |
| this.defaultFailureUrl = defaultFailureUrl; |
| } |
| |
| protected boolean isUseForward() { |
| return this.forwardToDestination; |
| } |
| |
| /** |
| * If set to <tt>true</tt>, performs a forward to the failure destination URL instead of a redirect. Defaults to |
| * <tt>false</tt>. |
| */ |
| public void setUseForward(final boolean forwardToDestination) { |
| this.forwardToDestination = forwardToDestination; |
| } |
| |
| /** |
| * Allows overriding of the behaviour when redirecting to a target URL. |
| */ |
| public void setRedirectStrategy(final RedirectStrategy redirectStrategy) { |
| this.redirectStrategy = redirectStrategy; |
| } |
| |
| protected RedirectStrategy getRedirectStrategy() { |
| return this.redirectStrategy; |
| } |
| |
| protected boolean isAllowSessionCreation() { |
| return this.allowSessionCreation; |
| } |
| |
| public void setAllowSessionCreation(final boolean allowSessionCreation) { |
| this.allowSessionCreation = allowSessionCreation; |
| } |
| } |