Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two realms in same application with Spring Security?

We're building a web application that is available to both authenticated and anonymous users. If you decide not to register/login you only have a limited set of features. User authentication is done over OpenID with Spring Security. That works fine.

However, the application also comes with an admin UI that is deployed at <host>/<context-root>/admin. Can we have two separate realms with Spring Security (e.g. basic auth for /admin/**)? How does that have to be configured?

like image 341
Marcel Stör Avatar asked Sep 08 '10 20:09

Marcel Stör


People also ask

Can we have two WebSecurityConfigurerAdapter?

When using Java configuration, the way to define multiple security realms is to have multiple @Configuration classes that extend the WebSecurityConfigurerAdapter base class – each with its own security configuration. These classes can be static and placed inside the main config.

What is realm in Spring Security?

A realm is a security policy domain defined for a web or application server. The protected resources on a server can be partitioned into a set of protection spaces, each with its own authentication scheme and/or authorization database containing a collection of users and groups.

Will Spring Security secures all the applications?

If Spring Security is on the classpath, Spring Boot automatically secures all HTTP endpoints with “basic” authentication. However, you can further customize the security settings. The first thing you need to do is add Spring Security to the classpath.


2 Answers

Spring Security has added support for this scenario in version 3.1, which is currently available as a Release Candidate. It was implemented by SEC-1171 and details of the syntax are in the manual included with 3.1.

However it's pretty simple to use. Basically you just define multiple http elements in your Spring Security configuration, one for each realm. We're using it like this:

<!-- Configure realm for system administration users -->
<security:http pattern="/admin/**" create-session="stateless">
    <security:intercept-url pattern='/**' access='ROLE_ADMIN' requires-channel="https" />
    <security:http-basic/>  
</security:http>


<!-- Configure realm for standard users -->
<security:http auto-config="true" access-denied-page="/error/noaccess" use-expressions="true" create-session="ifRequired">
    <security:form-login login-page="/login"
            ...
            ...
</security:http>

The key thing to note is the pattern="/admin/**" on the first http element. This tells Spring that all URLs under /admin are subject to that realm instead of the default realm — and thus URLs under /admin use basic authentication instead.

like image 88
gutch Avatar answered Oct 11 '22 15:10

gutch


Possible solution:

  • Add URL interceptor for /admin the requires "ROLE_ADMIN"
  • Configure instance of org.springframework.security.web.authentication.www.BasicAuthenticationFilter to intercept the /admin URL and authenticate user as ROLE_ADMIN if it provides the appropriate credentials

Sample configuration:

<security:intercept-url pattern="/admin" access="ROLE_ADMIN"/>

<bean id="basicAuthenticationEntryPoint" 
      class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
    <property name="realmName" 
              value="WS realm"/>
</bean>

<bean id="basicAuthenticationProcessingFilter"
      class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
    <property name="authenticationManager" 
              ref="authenticationManager"/>
    <property name="authenticationEntryPoint" 
              ref="basicAuthenticationEntryPoint"/>    
</bean>

Note: default implementation of BasicAuthenticationFilter is a passive filter, i.e. it just looks for a basic auth header in the request and if it is not present - does nothing. If you want the filter to explicitly require the basic authentication from the client, you need to extend the default implementation to commence to authentication entry point:

public class BasicAuthenticationFilter 
       extends org.springframework.security.web.authentication.www.BasicAuthenticationFilter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest request = (HttpServletRequest) req;
        final HttpServletResponse response = (HttpServletResponse) res;

        String header = request.getHeader("Authorization");

        if ((header != null) && header.startsWith("Basic ")) {
            super.doFilter(req, res, chain);
        } else {
            getAuthenticationEntryPoint().commence(request, response, new AuthenticationCredentialsNotFoundException("Missing credentials"));
        }
    }
}

In addition, you need to tweak the filter to apply to /admin URL only - either by hard-coding this in doFilter method or by providing an appropriate wrapper bean.

like image 27
Boris Kirzner Avatar answered Oct 11 '22 15:10

Boris Kirzner