CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-security--spring-security-remoting

Spring Security Remoting provides security services for remote method invocation in distributed Spring applications including RMI context propagation, HTTP invoker authentication, and DNS resolution utilities.

Pending
Overview
Eval results
Files

rmi-context-propagation.mddocs/

RMI Context Propagation

Security context propagation for RMI remoting, enabling transparent transmission of authentication information from client to server in distributed RMI applications. Maintains Spring Security context across JVM boundaries.

Deprecation Notice: RMI context propagation APIs are deprecated as of Spring Security 5.6.0 with no replacement.

Capabilities

Context Propagating Remote Invocation

Custom RemoteInvocation implementation that captures the security context on the client side and restores it on the server side during RMI method invocation.

public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
    /**
     * Constructs the object, storing the principal and credentials extracted 
     * from the client-side security context.
     * @param methodInvocation the method to invoke
     */
    public ContextPropagatingRemoteInvocation(MethodInvocation methodInvocation);

    /**
     * Invoked on the server-side. Creates an unauthenticated Authentication 
     * instance from transmitted principal and credentials for processing by 
     * the AuthenticationManager.
     * @param targetObject the target object to apply the invocation to
     * @return the invocation result
     * @throws NoSuchMethodException if the method name could not be resolved
     * @throws IllegalAccessException if the method could not be accessed
     * @throws InvocationTargetException if the method invocation resulted in an exception
     */
    public Object invoke(Object targetObject) 
        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException;

    /**
     * Creates the server-side authentication request object.
     * Default implementation creates UsernamePasswordAuthenticationToken with unauthenticated state.
     * Override to create different token types.
     * @param principal the transmitted principal
     * @param credentials the transmitted credentials  
     * @return Authentication instance for server-side processing
     */
    protected Authentication createAuthenticationRequest(String principal, String credentials);
}

Context Propagating Remote Invocation Factory

Factory for creating ContextPropagatingRemoteInvocation instances, used by RMI proxy factory beans to enable security context propagation.

public class ContextPropagatingRemoteInvocationFactory implements RemoteInvocationFactory {
    /**
     * Creates a remote invocation that propagates the current security context.
     * @param methodInvocation the method invocation to wrap
     * @return RemoteInvocation with security context propagation
     */
    public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation);
}

Usage Examples

Basic RMI Client Configuration

import org.springframework.remoting.rmi.RmiProxyFactoryBean;
import org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocationFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

// Define your service interface
public interface MyRemoteService {
    String processSecureRequest(String input);
    List<String> getUserData(String userId);
}

// Configure RMI proxy with security context propagation
RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();
proxy.setServiceUrl("rmi://localhost:1099/MyRemoteService");
proxy.setServiceInterface(MyRemoteService.class);
proxy.setRefreshStubOnConnectFailure(true);

// Add security context propagation
ContextPropagatingRemoteInvocationFactory factory = 
    new ContextPropagatingRemoteInvocationFactory();
proxy.setRemoteInvocationFactory(factory);

// Get the proxy instance
MyRemoteService service = (MyRemoteService) proxy.getObject();

// Use the service - security context will be propagated automatically
String result = service.processSecureRequest("sensitive data");

Spring Bean Configuration

<!-- RMI Proxy with Security Context Propagation -->
<bean id="myRemoteService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
    <property name="serviceUrl" value="rmi://localhost:1099/MyRemoteService"/>
    <property name="serviceInterface" value="com.example.MyRemoteService"/>
    <property name="refreshStubOnConnectFailure" value="true"/>
    <property name="remoteInvocationFactory" ref="contextPropagatingRemoteInvocationFactory"/>
</bean>

<!-- Remote Invocation Factory for Security Context Propagation -->
<bean id="contextPropagatingRemoteInvocationFactory"
      class="org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocationFactory"/>

Client-Side Usage with Security Context

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

// Set up authentication on the client side
Authentication auth = new UsernamePasswordAuthenticationToken("user", "password");
SecurityContextHolder.getContext().setAuthentication(auth);

try {
    // Remote call will propagate the security context to the server
    MyRemoteService service = getMyRemoteService(); // configured with ContextPropagatingRemoteInvocationFactory
    String result = service.processSecureRequest("confidential data");
    System.out.println("Result: " + result);
} finally {
    // Clean up client security context
    SecurityContextHolder.clearContext();
}

Server-Side RMI Service Configuration

import org.springframework.remoting.rmi.RmiServiceExporter;

// Server-side service implementation
@Component
public class MyRemoteServiceImpl implements MyRemoteService {
    
    @Override
    public String processSecureRequest(String input) {
        // Access the propagated security context
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.isAuthenticated()) {
            String username = auth.getName();
            // Process request with security context
            return "Processed by " + username + ": " + input;
        }
        throw new SecurityException("No authenticated user");
    }
}

// RMI service exporter configuration
@Bean
public RmiServiceExporter rmiServiceExporter(MyRemoteService myRemoteService) {
    RmiServiceExporter exporter = new RmiServiceExporter();
    exporter.setServiceName("MyRemoteService");
    exporter.setService(myRemoteService);
    exporter.setServiceInterface(MyRemoteService.class);
    exporter.setRegistryPort(1099);
    return exporter;
}

Custom Authentication Token Creation

import org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocation;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.Arrays;

public class CustomContextPropagatingRemoteInvocation extends ContextPropagatingRemoteInvocation {
    
    public CustomContextPropagatingRemoteInvocation(MethodInvocation methodInvocation) {
        super(methodInvocation);
    }
    
    @Override
    protected Authentication createAuthenticationRequest(String principal, String credentials) {
        // Create unauthenticated token (default implementation)
        return UsernamePasswordAuthenticationToken.unauthenticated(principal, credentials);
    }
}

// Custom factory to use the custom invocation
public class CustomRemoteInvocationFactory implements RemoteInvocationFactory {
    @Override
    public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
        return new CustomContextPropagatingRemoteInvocation(methodInvocation);
    }
}

Security Context Propagation Process

Client-Side Behavior

  1. Context Capture: When a remote method is called, ContextPropagatingRemoteInvocation extracts:
    • Principal name from current Authentication
    • Credentials as string from current Authentication
  2. Serialization: Principal and credentials are serialized as strings for transmission
  3. Transmission: The RemoteInvocation with security data is sent to the server

Server-Side Behavior

  1. Deserialization: Server receives the ContextPropagatingRemoteInvocation
  2. Authentication Creation: Creates unauthenticated UsernamePasswordAuthenticationToken from transmitted data
  3. Context Setup: Sets up SecurityContext with the Authentication before method execution
  4. Method Execution: Target method executes with security context available
  5. Context Cleanup: SecurityContext is cleared after method execution completes

Security Considerations

  • Credentials Transmission: Credentials are transmitted as plaintext strings - ensure secure transport (SSL/TLS)
  • Authentication State: Transmitted authentication is marked as unauthenticated, requiring server-side authentication
  • Token Type: Default implementation creates UsernamePasswordAuthenticationToken - override for custom token types
  • Serialization Safety: Implementation interprets values as strings to avoid serialization-based attacks

Integration with Spring Security

Server-Side Authentication

The propagated authentication typically requires server-side processing:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class RmiSecurityConfig {
    
    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService());
        provider.setPasswordEncoder(passwordEncoder());
        return new ProviderManager(provider);
    }
    
    // Configure authentication for RMI services
    @Bean
    public MethodSecurityInterceptor methodSecurityInterceptor() {
        MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();
        interceptor.setAuthenticationManager(authenticationManager());
        // Configure access decision manager
        return interceptor;
    }
}

Method-Level Security

@Component
public class SecureRemoteServiceImpl implements SecureRemoteService {
    
    @PreAuthorize("hasRole('USER')")
    public String processUserRequest(String request) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return "Processed by " + auth.getName() + ": " + request;
    }
    
    @PreAuthorize("hasRole('ADMIN')")
    public void performAdminOperation() {
        // Admin-only operation
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-security--spring-security-remoting

docs

dns-resolution.md

http-invoker-auth.md

index.md

rmi-context-propagation.md

tile.json