or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dns-resolution.mdhttp-invoker-auth.mdindex.mdrmi-context-propagation.md

rmi-context-propagation.mddocs/

0

# RMI Context Propagation

1

2

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.

3

4

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

5

6

## Capabilities

7

8

### Context Propagating Remote Invocation

9

10

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

11

12

```java { .api }

13

public class ContextPropagatingRemoteInvocation extends RemoteInvocation {

14

/**

15

* Constructs the object, storing the principal and credentials extracted

16

* from the client-side security context.

17

* @param methodInvocation the method to invoke

18

*/

19

public ContextPropagatingRemoteInvocation(MethodInvocation methodInvocation);

20

21

/**

22

* Invoked on the server-side. Creates an unauthenticated Authentication

23

* instance from transmitted principal and credentials for processing by

24

* the AuthenticationManager.

25

* @param targetObject the target object to apply the invocation to

26

* @return the invocation result

27

* @throws NoSuchMethodException if the method name could not be resolved

28

* @throws IllegalAccessException if the method could not be accessed

29

* @throws InvocationTargetException if the method invocation resulted in an exception

30

*/

31

public Object invoke(Object targetObject)

32

throws NoSuchMethodException, IllegalAccessException, InvocationTargetException;

33

34

/**

35

* Creates the server-side authentication request object.

36

* Default implementation creates UsernamePasswordAuthenticationToken with unauthenticated state.

37

* Override to create different token types.

38

* @param principal the transmitted principal

39

* @param credentials the transmitted credentials

40

* @return Authentication instance for server-side processing

41

*/

42

protected Authentication createAuthenticationRequest(String principal, String credentials);

43

}

44

```

45

46

### Context Propagating Remote Invocation Factory

47

48

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

49

50

```java { .api }

51

public class ContextPropagatingRemoteInvocationFactory implements RemoteInvocationFactory {

52

/**

53

* Creates a remote invocation that propagates the current security context.

54

* @param methodInvocation the method invocation to wrap

55

* @return RemoteInvocation with security context propagation

56

*/

57

public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation);

58

}

59

```

60

61

## Usage Examples

62

63

### Basic RMI Client Configuration

64

65

```java

66

import org.springframework.remoting.rmi.RmiProxyFactoryBean;

67

import org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocationFactory;

68

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

69

70

// Define your service interface

71

public interface MyRemoteService {

72

String processSecureRequest(String input);

73

List<String> getUserData(String userId);

74

}

75

76

// Configure RMI proxy with security context propagation

77

RmiProxyFactoryBean proxy = new RmiProxyFactoryBean();

78

proxy.setServiceUrl("rmi://localhost:1099/MyRemoteService");

79

proxy.setServiceInterface(MyRemoteService.class);

80

proxy.setRefreshStubOnConnectFailure(true);

81

82

// Add security context propagation

83

ContextPropagatingRemoteInvocationFactory factory =

84

new ContextPropagatingRemoteInvocationFactory();

85

proxy.setRemoteInvocationFactory(factory);

86

87

// Get the proxy instance

88

MyRemoteService service = (MyRemoteService) proxy.getObject();

89

90

// Use the service - security context will be propagated automatically

91

String result = service.processSecureRequest("sensitive data");

92

```

93

94

### Spring Bean Configuration

95

96

```xml

97

<!-- RMI Proxy with Security Context Propagation -->

98

<bean id="myRemoteService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">

99

<property name="serviceUrl" value="rmi://localhost:1099/MyRemoteService"/>

100

<property name="serviceInterface" value="com.example.MyRemoteService"/>

101

<property name="refreshStubOnConnectFailure" value="true"/>

102

<property name="remoteInvocationFactory" ref="contextPropagatingRemoteInvocationFactory"/>

103

</bean>

104

105

<!-- Remote Invocation Factory for Security Context Propagation -->

106

<bean id="contextPropagatingRemoteInvocationFactory"

107

class="org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocationFactory"/>

108

```

109

110

### Client-Side Usage with Security Context

111

112

```java

113

import org.springframework.security.core.Authentication;

114

import org.springframework.security.core.context.SecurityContextHolder;

115

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

116

117

// Set up authentication on the client side

118

Authentication auth = new UsernamePasswordAuthenticationToken("user", "password");

119

SecurityContextHolder.getContext().setAuthentication(auth);

120

121

try {

122

// Remote call will propagate the security context to the server

123

MyRemoteService service = getMyRemoteService(); // configured with ContextPropagatingRemoteInvocationFactory

124

String result = service.processSecureRequest("confidential data");

125

System.out.println("Result: " + result);

126

} finally {

127

// Clean up client security context

128

SecurityContextHolder.clearContext();

129

}

130

```

131

132

### Server-Side RMI Service Configuration

133

134

```java

135

import org.springframework.remoting.rmi.RmiServiceExporter;

136

137

// Server-side service implementation

138

@Component

139

public class MyRemoteServiceImpl implements MyRemoteService {

140

141

@Override

142

public String processSecureRequest(String input) {

143

// Access the propagated security context

144

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

145

if (auth != null && auth.isAuthenticated()) {

146

String username = auth.getName();

147

// Process request with security context

148

return "Processed by " + username + ": " + input;

149

}

150

throw new SecurityException("No authenticated user");

151

}

152

}

153

154

// RMI service exporter configuration

155

@Bean

156

public RmiServiceExporter rmiServiceExporter(MyRemoteService myRemoteService) {

157

RmiServiceExporter exporter = new RmiServiceExporter();

158

exporter.setServiceName("MyRemoteService");

159

exporter.setService(myRemoteService);

160

exporter.setServiceInterface(MyRemoteService.class);

161

exporter.setRegistryPort(1099);

162

return exporter;

163

}

164

```

165

166

### Custom Authentication Token Creation

167

168

```java

169

import org.springframework.security.remoting.rmi.ContextPropagatingRemoteInvocation;

170

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

171

import org.springframework.security.core.Authentication;

172

import org.springframework.security.core.authority.SimpleGrantedAuthority;

173

import java.util.Arrays;

174

175

public class CustomContextPropagatingRemoteInvocation extends ContextPropagatingRemoteInvocation {

176

177

public CustomContextPropagatingRemoteInvocation(MethodInvocation methodInvocation) {

178

super(methodInvocation);

179

}

180

181

@Override

182

protected Authentication createAuthenticationRequest(String principal, String credentials) {

183

// Create unauthenticated token (default implementation)

184

return UsernamePasswordAuthenticationToken.unauthenticated(principal, credentials);

185

}

186

}

187

188

// Custom factory to use the custom invocation

189

public class CustomRemoteInvocationFactory implements RemoteInvocationFactory {

190

@Override

191

public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {

192

return new CustomContextPropagatingRemoteInvocation(methodInvocation);

193

}

194

}

195

```

196

197

## Security Context Propagation Process

198

199

### Client-Side Behavior

200

201

1. **Context Capture**: When a remote method is called, ContextPropagatingRemoteInvocation extracts:

202

- Principal name from current Authentication

203

- Credentials as string from current Authentication

204

2. **Serialization**: Principal and credentials are serialized as strings for transmission

205

3. **Transmission**: The RemoteInvocation with security data is sent to the server

206

207

### Server-Side Behavior

208

209

1. **Deserialization**: Server receives the ContextPropagatingRemoteInvocation

210

2. **Authentication Creation**: Creates unauthenticated UsernamePasswordAuthenticationToken from transmitted data

211

3. **Context Setup**: Sets up SecurityContext with the Authentication before method execution

212

4. **Method Execution**: Target method executes with security context available

213

5. **Context Cleanup**: SecurityContext is cleared after method execution completes

214

215

### Security Considerations

216

217

- **Credentials Transmission**: Credentials are transmitted as plaintext strings - ensure secure transport (SSL/TLS)

218

- **Authentication State**: Transmitted authentication is marked as unauthenticated, requiring server-side authentication

219

- **Token Type**: Default implementation creates UsernamePasswordAuthenticationToken - override for custom token types

220

- **Serialization Safety**: Implementation interprets values as strings to avoid serialization-based attacks

221

222

## Integration with Spring Security

223

224

### Server-Side Authentication

225

226

The propagated authentication typically requires server-side processing:

227

228

```java

229

@Configuration

230

@EnableGlobalMethodSecurity(prePostEnabled = true)

231

public class RmiSecurityConfig {

232

233

@Bean

234

public AuthenticationManager authenticationManager() {

235

DaoAuthenticationProvider provider = new DaoAuthenticationProvider();

236

provider.setUserDetailsService(userDetailsService());

237

provider.setPasswordEncoder(passwordEncoder());

238

return new ProviderManager(provider);

239

}

240

241

// Configure authentication for RMI services

242

@Bean

243

public MethodSecurityInterceptor methodSecurityInterceptor() {

244

MethodSecurityInterceptor interceptor = new MethodSecurityInterceptor();

245

interceptor.setAuthenticationManager(authenticationManager());

246

// Configure access decision manager

247

return interceptor;

248

}

249

}

250

```

251

252

### Method-Level Security

253

254

```java

255

@Component

256

public class SecureRemoteServiceImpl implements SecureRemoteService {

257

258

@PreAuthorize("hasRole('USER')")

259

public String processUserRequest(String request) {

260

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

261

return "Processed by " + auth.getName() + ": " + request;

262

}

263

264

@PreAuthorize("hasRole('ADMIN')")

265

public void performAdminOperation() {

266

// Admin-only operation

267

}

268

}