Allow forward URL to choose HTTP method in SPNEGO
Closes gh-108
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009-2015 the original author or authors.
|
||||
* Copyright 2009-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@ package org.springframework.security.kerberos.web.authentication;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -57,6 +59,8 @@ public class SpnegoEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
private final String forwardUrl;
|
||||
|
||||
private final HttpMethod forwardMethod;
|
||||
|
||||
private final boolean forward;
|
||||
|
||||
/**
|
||||
@@ -71,8 +75,8 @@ public class SpnegoEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
/**
|
||||
* Instantiates a new spnego entry point. This constructor enables security
|
||||
* configuration to use SPNEGO in combination with login form as fallback
|
||||
* for clients that do not support this kind of authentication.
|
||||
* configuration to use SPNEGO in combination with a fallback page (login form,
|
||||
* custom 401 page ...). The forward method will be the same as the original request.
|
||||
*
|
||||
* @param forwardUrl
|
||||
* URL where the login page can be found. Should be
|
||||
@@ -80,13 +84,34 @@ public class SpnegoEntryPoint implements AuthenticationEntryPoint {
|
||||
* {@code /}) and can't be absolute URL.
|
||||
*/
|
||||
public SpnegoEntryPoint(String forwardUrl) {
|
||||
this(forwardUrl, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new spnego entry point. This constructor enables security
|
||||
* configuration to use SPNEGO in combination a fallback page (login form,
|
||||
* custom 401 page ...). The forward URL will be accessed via provided HTTP
|
||||
* method.
|
||||
*
|
||||
* @param forwardUrl
|
||||
* URL where the login page can be found. Should be
|
||||
* relative to the web-app context path (include a leading
|
||||
* {@code /}) and can't be absolute URL.
|
||||
*
|
||||
* @param forwardMethod
|
||||
* HTTP method to use when accessing the forward URL
|
||||
*/
|
||||
public SpnegoEntryPoint(String forwardUrl, HttpMethod forwardMethod) {
|
||||
if (StringUtils.hasText(forwardUrl)) {
|
||||
Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), "Forward url specified must be a valid forward URL");
|
||||
Assert.isTrue(!UrlUtils.isAbsoluteUrl(forwardUrl), "Forward url specified must not be absolute");
|
||||
|
||||
this.forwardUrl = forwardUrl;
|
||||
this.forwardMethod = forwardMethod;
|
||||
this.forward = true;
|
||||
} else {
|
||||
this.forwardUrl = null;
|
||||
this.forwardMethod = null;
|
||||
this.forward = false;
|
||||
}
|
||||
}
|
||||
@@ -102,7 +127,13 @@ public class SpnegoEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
if (forward) {
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
|
||||
dispatcher.forward(request, response);
|
||||
HttpServletRequest fwdRequest = forwardMethod != null ? new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return forwardMethod.name();
|
||||
}
|
||||
} : request;
|
||||
dispatcher.forward(fwdRequest, response);
|
||||
} else {
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
@@ -17,10 +17,14 @@ package org.springframework.security.kerberos.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -28,6 +32,7 @@ import static org.mockito.Mockito.when;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Test class for {@link SpnegoEntryPoint}
|
||||
@@ -79,6 +84,35 @@ public class SpnegoEntryPointTest {
|
||||
verify(requestDispatcher).forward(request, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForwardUsesDefaultHttpMethod() throws Exception {
|
||||
ArgumentCaptor<HttpServletRequest> servletRequestCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
||||
String forwardUrl = "/login";
|
||||
SpnegoEntryPoint entryPoint = new SpnegoEntryPoint(forwardUrl);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getMethod()).thenReturn(RequestMethod.POST.name());
|
||||
RequestDispatcher requestDispatcher = mock(RequestDispatcher.class);
|
||||
when(request.getRequestDispatcher(anyString())).thenReturn(requestDispatcher);
|
||||
entryPoint.commence(request, response, null);
|
||||
verify(requestDispatcher).forward(servletRequestCaptor.capture(), eq(response));
|
||||
assertThat(servletRequestCaptor.getValue().getMethod()).isEqualTo(HttpMethod.POST.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForwardUsesCustomHttpMethod() throws Exception {
|
||||
ArgumentCaptor<HttpServletRequest> servletRequestCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
||||
String forwardUrl = "/login";
|
||||
SpnegoEntryPoint entryPoint = new SpnegoEntryPoint(forwardUrl, HttpMethod.DELETE);
|
||||
HttpServletResponse response = mock(HttpServletResponse.class);
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
RequestDispatcher requestDispatcher = mock(RequestDispatcher.class);
|
||||
when(request.getRequestDispatcher(anyString())).thenReturn(requestDispatcher);
|
||||
entryPoint.commence(request, response, null);
|
||||
verify(requestDispatcher).forward(servletRequestCaptor.capture(), eq(response));
|
||||
assertThat(servletRequestCaptor.getValue().getMethod()).isEqualTo(HttpMethod.DELETE.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntryPointForwardAbsolute() throws Exception {
|
||||
assertThatThrownBy(() -> {
|
||||
|
||||
Reference in New Issue
Block a user