spring-securityweblogicspring-security-ldap

How can Spring Security validate a AD user whose Authentication Provider is configured on WebLogic?


Use-case:

I have a Spring Boot application v2.7.x. For the security, i am trying to configure a SecurityFilterChain that will point to an authentication provider (LDAP) that is configured in WebLogic v14.x.x.

The WebLogic configuration for the LDAP has been done here:

Security Realms > myrealm > Providers > Authentication tab

Question:

How do i point the Spring Boot Application to use that WebLogic Authentication Provider i.e the Spring Security configuration. Probably, something like here under LDAP Authentication section?


As a side-note, I will probably be needing these:

pom.xml
<dependency>
    <groupId>com.oracle.weblogic</groupId>
    <artifactId>weblogic-server-pom</artifactId>
    <version>12.2.1.4</version> <!-- Use the appropriate version for your WebLogic installation -->
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.oracle.weblogic</groupId>
    <artifactId>wlthint3client</artifactId>
    <version>12.2.1.4</version> <!-- Use the appropriate version for your WebLogic installation -->
    <scope>provided</scope>
</dependency>

weblogic.xml
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app">
    <security-role-assignment>
        <role-name>authenticated-users</role-name>
        <principal-name>users</principal-name> 
    </security-role-assignment>
</weblogic-web-app>

Note:

I do not want to use an ActiveDirectoryLdapAuthenticationProvider that is pointing directly to the AD.

The final answer would probably be an extension of these 2 SO posts, this and this.

Authentication Provider (LDAP) configured in WebLogic:

enter image description here


Solution

  • I have a spring boot application deployed in weblogic 12.2.1.4 that uses weblogic authentication. I have it configured as below...

    src/main/webapp/WEB-INF/web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
    
      <context-param>
        <param-name>spring.profiles.active</param-name>
        <param-value>default</param-value>
      </context-param>
      
      <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
          <form-login-page>/login</form-login-page>
          <form-error-page>/login</form-error-page>
        </form-login-config>
      </login-config>
    
      <security-role>
        <role-name>USER</role-name>
      </security-role>
      
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>Jobs</web-resource-name>
          <url-pattern>/jobs/*</url-pattern>
        </web-resource-collection>
        <web-resource-collection>
          <web-resource-name>Executions</web-resource-name>
          <url-pattern>/executions/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
          <role-name>USER</role-name>
        </auth-constraint>
        <user-data-constraint>
          <description>This is how the user data must be transmitted</description>
          <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
      </security-constraint>
    
    </web-app>
    

    src/main/webapp/WEB-INF/weblogic.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
      <context-root>cmx-customer-file-faker</context-root>
      <container-descriptor>
        <prefer-application-packages>
          <package-name>org.slf4j.*</package-name>
          <package-name>org.springframework.*</package-name>
          <package-name>com.fasterxml.jackson.*</package-name>
        </prefer-application-packages>
    
        <prefer-application-resources>
          <resource-name>org/slf4j/impl/StaticLoggerBinder.class</resource-name>
        </prefer-application-resources>
      </container-descriptor>
      
      <security-role-assignment>
        <role-name>USER</role-name>
        <principal-name>users</principal-name>
      </security-role-assignment>
    </weblogic-web-app>
    

    WebSecurityConfig - this is where spring security is configured to use weblogic authentication via the J2eePreAuthenticatedProcessingFilter

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Bean
        public MappableAttributesRetriever webXmlRolesParser() {
            return new WebXmlMappableAttributesRetriever();
        }
    
        @Bean
        public Attributes2GrantedAuthoritiesMapper roles2GrantedAuthoritiesMapper() {
            SimpleAttributes2GrantedAuthoritiesMapper var = new SimpleAttributes2GrantedAuthoritiesMapper();
            var.setAttributePrefix("");
            return var;
        }
    
        @Bean
        public J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource authenticationDetailsSource() {
            J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource var = new J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource();
            var.setMappableRolesRetriever(webXmlRolesParser());
            var.setUserRoles2GrantedAuthoritiesMapper(roles2GrantedAuthoritiesMapper());
            return var;
        }
    
        @Bean
        public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getUserDetailsService() {
            return new PreAuthenticatedGrantedAuthoritiesUserDetailsService();
        }
    
        @Bean
        public AuthenticationProvider preAuthenticatedAuthenticationProvider() {
            PreAuthenticatedAuthenticationProvider var = new PreAuthenticatedAuthenticationProvider();
            var.setPreAuthenticatedUserDetailsService(getUserDetailsService());
            return var;
        }
    
        @Override
        @Bean
        public AuthenticationManager authenticationManager() {
            return new ProviderManager(Arrays.asList(preAuthenticatedAuthenticationProvider()));
        }
    
        @Bean
        public J2eePreAuthenticatedProcessingFilter j2eePreAuthFilter() {
            J2eePreAuthenticatedProcessingFilter var = new J2eePreAuthenticatedProcessingFilter();
            var.setAuthenticationDetailsSource(authenticationDetailsSource());
            var.setAuthenticationManager(authenticationManager());
            return var;
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterAfter(j2eePreAuthFilter(), AbstractPreAuthenticatedProcessingFilter.class)
                    .authorizeRequests()
                    .anyRequest()
                    .permitAll()
                    .and()
                    .logout().logoutSuccessUrl("/bye")
                    .and()
                    .csrf().disable();
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/webjars/**", "/login");
            super.configure(web);
        }
    
    }
    

    LoginController

    @Controller
    public class LoginController {
    
        @RequestMapping("/login")
        public String getLoginForm(HttpServletRequest request, Model model) {
            return "login";
        }
    
        @GetMapping("/bye")
        public String logoutSuccess() {
            return "logout";
        }
    
    }
    

    login.ftlh - my freemarker template for the login page.

    <#import "/spring.ftl" as spring />
    
    <!DOCTYPE html>  
    <html lang="en">  
    <head>  
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="<@spring.url '/webjars/bootstrap/5.1.3/css/bootstrap.min.css'/>"/>
        <link rel="stylesheet" href="<@spring.url '/webjars/font-awesome/5.15.4/css/all.min.css'/>"/>
        
        <style>
        .fas.btn {
            font-weight: 900;
        }
        </style>
    
    </head>  
    <body>  
        <nav class="navbar navbar-expand-lg navbar-light" style="background-color: rgb(248, 249, 250)">
          <div class="container">
            <a class="navbar-brand" href="<@spring.url '/'/>">Login</a>
          </div>
        </nav>  
        
        <div class="mt-5 container">
            <div class="row justify-content-center">
                <div class="col-8">
                    <#if Request['javax.servlet.error.message']??>
                    <div class="alert alert-danger alert-dismissible fade show mb-5" role="alert">
                        ${Request['javax.servlet.error.message']}
                        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                    </div>
                    </#if>
                    <form class="card" method="POST" action="j_security_check">
                        <div class="card-header">
                            <h5>Enter your login details</h5>
                        </div>
                        <div class="card-body">
                            <div class="mb-3">
                                <label for="InputUserName" class="form-label">User Name</label>
                                <input name="j_username" class="form-control" id="InputUserName" aria-describedby="userNameHelp">
                            </div>
                            <div class="mb-3">
                                <label for="InputPassword" class="form-label">Password</label>
                                <input name="j_password" type="password" class="form-control" id="InputPassword">
                            </div>
                            <button type="submit" class="btn btn-primary">Login</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        
        <script src="<@spring.url '/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js'/>"></script>
    </body>  
    </html>
    

    pom.xml spring boot dependencies

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>5.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>font-awesome</artifactId>
            <version>5.15.4</version>
        </dependency>
        ...
    </dependencies>