/src/main/src/main/java/org/geoserver/security/filter/GeoServerPreAuthenticationFilter.java

https://github.com/geoserver/geoserver · Java · 165 lines · 115 code · 25 blank · 25 comment · 19 complexity · a248cd16827b1903087429b85ea3e300 MD5 · raw file

  1. /* (c) 2014 Open Source Geospatial Foundation - all rights reserved
  2. * (c) 2001 - 2013 OpenPlans
  3. * This code is licensed under the GPL 2.0 license, available at the root
  4. * application directory.
  5. */
  6. package org.geoserver.security.filter;
  7. import java.io.IOException;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.Collections;
  11. import java.util.logging.Level;
  12. import javax.servlet.FilterChain;
  13. import javax.servlet.ServletException;
  14. import javax.servlet.ServletRequest;
  15. import javax.servlet.ServletResponse;
  16. import javax.servlet.http.HttpServletRequest;
  17. import javax.servlet.http.HttpServletResponse;
  18. import org.geoserver.security.config.SecurityNamedServiceConfig;
  19. import org.geoserver.security.impl.GeoServerRole;
  20. import org.geoserver.security.impl.GeoServerUser;
  21. import org.springframework.security.authentication.AuthenticationDetailsSource;
  22. import org.springframework.security.core.Authentication;
  23. import org.springframework.security.core.context.SecurityContextHolder;
  24. import org.springframework.security.web.AuthenticationEntryPoint;
  25. import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
  26. import org.springframework.security.web.authentication.WebAuthenticationDetails;
  27. import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
  28. import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
  29. /**
  30. * Abstract base class for pre-authentication filters
  31. *
  32. * @author christian
  33. */
  34. public abstract class GeoServerPreAuthenticationFilter extends GeoServerSecurityFilter
  35. implements AuthenticationCachingFilter, GeoServerAuthenticationFilter {
  36. private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails>
  37. authenticationDetailsSource = new WebAuthenticationDetailsSource();
  38. protected AuthenticationEntryPoint aep;
  39. @Override
  40. public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
  41. super.initializeFromConfig(config);
  42. aep = new Http403ForbiddenEntryPoint();
  43. }
  44. /** Try to authenticate if there is no authenticated principal */
  45. @Override
  46. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  47. throws IOException, ServletException {
  48. String cacheKey = authenticateFromCache(this, (HttpServletRequest) request);
  49. if (SecurityContextHolder.getContext().getAuthentication() == null) {
  50. doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
  51. Authentication postAuthentication =
  52. SecurityContextHolder.getContext().getAuthentication();
  53. if (postAuthentication != null && cacheKey != null) {
  54. if (cacheAuthentication(postAuthentication, (HttpServletRequest) request)) {
  55. getSecurityManager()
  56. .getAuthenticationCache()
  57. .put(getName(), cacheKey, postAuthentication);
  58. }
  59. }
  60. }
  61. request.setAttribute(GeoServerSecurityFilter.AUTHENTICATION_ENTRY_POINT_HEADER, aep);
  62. chain.doFilter(request, response);
  63. }
  64. /**
  65. * subclasses should return the principal, <code>null</code> if no principal was authenticated
  66. */
  67. protected abstract String getPreAuthenticatedPrincipal(HttpServletRequest request);
  68. /**
  69. * subclasses should return the roles for the principal obtained by {@link
  70. * #getPreAuthenticatedPrincipal(HttpServletRequest)}
  71. */
  72. protected abstract Collection<GeoServerRole> getRoles(
  73. HttpServletRequest request, String principal) throws IOException;
  74. /**
  75. * Try to authenticate and adds {@link GeoServerRole#AUTHENTICATED_ROLE} Takes care of the
  76. * special user named {@link GeoServerUser#ROOT_USERNAME}
  77. */
  78. protected void doAuthenticate(HttpServletRequest request, HttpServletResponse response) {
  79. String principal = getPreAuthenticatedPrincipal(request);
  80. if (principal == null || principal.trim().length() == 0) {
  81. return;
  82. }
  83. LOGGER.log(
  84. Level.FINE,
  85. "preAuthenticatedPrincipal = " + principal + ", trying to authenticate");
  86. PreAuthenticatedAuthenticationToken result = null;
  87. if (GeoServerUser.ROOT_USERNAME.equals(principal)) {
  88. result =
  89. new PreAuthenticatedAuthenticationToken(
  90. principal, null, Collections.singleton(GeoServerRole.ADMIN_ROLE));
  91. } else {
  92. Collection<GeoServerRole> roles = null;
  93. try {
  94. roles = new ArrayList<>(getRoles(request, principal));
  95. } catch (IOException e) {
  96. throw new RuntimeException(e);
  97. }
  98. if (roles.contains(GeoServerRole.AUTHENTICATED_ROLE) == false)
  99. roles.add(GeoServerRole.AUTHENTICATED_ROLE);
  100. result = new PreAuthenticatedAuthenticationToken(principal, null, roles);
  101. }
  102. result.setDetails(authenticationDetailsSource.buildDetails(request));
  103. SecurityContextHolder.getContext().setAuthentication(result);
  104. }
  105. public AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails>
  106. getAuthenticationDetailsSource() {
  107. return authenticationDetailsSource;
  108. }
  109. public void setAuthenticationDetailsSource(
  110. AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails>
  111. authenticationDetailsSource) {
  112. this.authenticationDetailsSource = authenticationDetailsSource;
  113. }
  114. @Override
  115. public AuthenticationEntryPoint getAuthenticationEntryPoint() {
  116. return aep;
  117. }
  118. protected boolean cacheAuthentication(Authentication auth, HttpServletRequest request) {
  119. // only cache if no HTTP session is available
  120. return request.getSession(false) == null;
  121. }
  122. @Override
  123. public String getCacheKey(HttpServletRequest request) {
  124. if (request.getSession(false) != null) // no caching if there is an HTTP session
  125. return null;
  126. String retval = getPreAuthenticatedPrincipal(request);
  127. if (GeoServerUser.ROOT_USERNAME.equals(retval)) return null;
  128. return retval;
  129. }
  130. /** @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForHtml() */
  131. @Override
  132. public boolean applicableForHtml() {
  133. return true;
  134. }
  135. /** @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForServices() */
  136. @Override
  137. public boolean applicableForServices() {
  138. return true;
  139. }
  140. }