Timeouts are not correct for servlet in spring boot - spring-boot

This is remote server properties:
server.servlet.session.timeout=3m
SAme for my local.properties
also we have a config like this:
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/login?invalidSession")//dokunma
.maximumSessions(1)//
.maxSessionsPreventsLogin(true)//
.expiredUrl("/login?expired")
.sessionRegistry(sessionRegistry());
We have a class like this:
#Bean // Http Listener
public HttpSessionListener httpSessionListener() {
return new HttpSessionListener() {
#Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
if (session != null) {
LoggerService.logger.info("sessionCreated sessionid: {}, setMaxInactiveInterval: {}, ipaddress: {}",
session.getId(), session.getMaxInactiveInterval(), SecurityUtil.getIpAddress());
I did this to see internal times.
But on server, i see this log:
sessionCreated sessionid: 342E6139B2FE108D26537C9D684FBFF3, setMaxInactiveInterval: 1800, ipaddress: null
It must be 180, not 1800. Why does it multiply?
We dont have any other codes to set this. For example:
request.getSession(false).setMaxInactiveInterval(11);
We dont have this. But i will use this if i cant find any solution.
For example, for remote, i changed to this:
server.servlet.session.timeout=44s
But what i see is:
sessionCreated sessionid: 7C3573FE7B5FB6C8939DF8BF60B1B550, setMaxInactiveInterval: 1800, ipaddress: null
Tomcat9 is doing this?
On my local, i use that properties to test.
So
server.servlet.session.timeout=44s
for my local and remote server database configurations for my local.
But this time:
sessionCreated sessionid: 747E6BF3DCD061DFF306325FE4FD76B6, getMaxInactiveInterval: 60, ipaddress: 0:0:0:0:0:0:0:1
747E6BF3DCD061DFF306325FE4FD76B6 0:0:0:0:0:0:0:1 Session Created
What am i doing wrong?
FOr last test, i added this to success handler for my local but with remote properties:
LoggerService.logger.info("onAuthenticationSuccess sessionid: {}, getMaxInactiveInterval: {}, ipaddress: {}",
session.getId(), session.getMaxInactiveInterval(), SecurityUtil.getIpAddress());
request.getSession(false).setMaxInactiveInterval(55);
LoggerService.logger.info("onAuthenticationSuccess sessionid: {}, getMaxInactiveInterval: {}, ipaddress: {}",
session.getId(), session.getMaxInactiveInterval(), SecurityUtil.getIpAddress());
If i put my username password, i can see this:
: onAuthenticationSuccess sessionid: F796EA6C54D8BCA239A36E02C4A7A030, getMaxInactiveInterval: 60, ipaddress: 0:0:0:0:0:0:0:1
: onAuthenticationSuccess sessionid: F796EA6C54D8BCA239A36E02C4A7A030, getMaxInactiveInterval: 55, ipaddress: 0:0:0:0:0:0:0:1
I also did this:
#Bean // Http Listener
public HttpSessionListener httpSessionListener() {
return new HttpSessionListener() {
#Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
if (session != null) {
LoggerService.logger.info("sessionCreated sessionid: {}, setMaxInactiveInterval: {}, ipaddress: {}",
session.getId(), session.getMaxInactiveInterval(), SecurityUtil.getIpAddress());
session.setMaxInactiveInterval(55);
LoggerService.logger.info("sessionCreated sessionid: {}, setMaxInactiveInterval: {}, ipaddress: {}",
session.getId(), session.getMaxInactiveInterval(), SecurityUtil.getIpAddress());
It is again same:
sessionCreated sessionid: FFA7DC9A6558951F1CB790AD9D804F88, getMaxInactiveInterval: 60, ipaddress: null
sessionCreated sessionid: FFA7DC9A6558951F1CB790AD9D804F88, getMaxInactiveInterval: 55, ipaddress: null
FFA7DC9A6558951F1CB790AD9D804F88 0:0:0:0:0:0:0:1 Session Created
For remote, i tested with same code and also it worked but i dont want to set programatically
sessionCreated before sessionid: 38EC29F7C9C45B34D1FDF05B1F90DC3A, getMaxInactiveInterval: 1800, ipaddress: 192.ss
sessionCreated after sessionid: 38EC29F7C9C45B34D1FDF05B1F90DC3A, getMaxInactiveInterval: 180, ipaddress: 192.ss
So, there are two problems:
Why is application-remote-properties timeout value not working for local?
Why is remote timeout multiplied by 10 (properties has 3m but log shows 1800s)

The server.* properties are used to control the embedded container used by Spring Boot. Spring Boot will create an instance of the servlet container using one of the ServletWebServerFactory instances. These classes use the server.* properties to configure the controlled servlet container (tomcat, jetty etc).
However when you are deploying the application as a war file to a Tomcat instance the server.* properties don't apply. They don't apply because a pre-configured servlet container is available (as it is a remotely running service). So deploying to a remote Tomcat will make the server.* properties useless.
Regarding the session timeout being in minutes. Spring Boot will convert the session.servlet.session.timeout property to minutes, so 44s or 55s will be automatically converted to 1 minute. Setting it to something less then a minute also will not make much sense as Tomcat invalidates session with a thread running each minute.

Related

Spring Boot: Connection timed out when trying to call a service from a service

I have 2 microservices + an Eureka Server in which they are registerd.
I made really everything I could think of, yet when I try to call the login service from the manager service, I always get "Connection timed out".
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
I have tried to work with Spring RestTemplate and WebClient and also Apache HttpClient.
All the times, the flow reaches the post method, and I get the same result.
I guess it must be some configuration issue.
I am working on localhost with all modules.
It really drives me crzay!
Please advise. I appreciate it.
The relevant info is as follows. Please tell me if you need more info.
First of all you can see that the services are registered and up:
Next the code:
Manager (calling) Service:
(I left inside all my previous attempts commented)
#PostMapping("/login")
public void login(#RequestBody LoginRequest loginRequest) throws Exception {
String url = getBaseUrl("bbsim-login-service") + "/api/auth/signin";
/* CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(getBaseUrl("bbsim-login-service") + "/api/auth/signin");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", loginRequest.getUsername()));
params.add(new BasicNameValuePair("password", loginRequest.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = httpclient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
*/
/* HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connect timeout: time is in milliseconds
clientHttpRequestFactory.setConnectTimeout(30000);
// Read timeout: time is in milliseconds
clientHttpRequestFactory.setReadTimeout(30000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
HttpEntity<LoginRequest> request = new HttpEntity<>(loginRequest);
JwtResponse res = restTemplate.postForObject(url, request, JwtResponse.class);
System.out.println(res);
*/
localApiClient
.post()
.uri(url)
.body(Mono.just(loginRequest), LoginRequest.class)
.retrieve()
.bodyToMono(JwtResponse.class)
.block();
}
private String getBaseUrl(String serviceName) {
Application application = eurekaClient.getApplication(serviceName);
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;
}
application.yml:
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
If I understand well, the request does not reach the login service at all.
Login (called) service:
#PostMapping("/signin")
public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok().body(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
application.yml file:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
I addition, I tried the following - giving me the same results:
curl -d "#data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
where data.json has the body contents.
This will not be a complete answer but I hope it helps you with your issue.
I think your problem could be related with a mix of the different IP address of your machine.
First, I think Eureka is exposing your services like host.docker.internal, as indicated, the logical name that references the host machine through the different docker containers, for the reason explained in this SO question.
Basically, it seems that the docker software is updating your hosts file with entries for host.docker.internal and gateway.docker.internal and Eureka probably is taking that alias as the one for the machine IP that is being advertised. Please, see the accepted answer in the aforementioned question.
When you run Spring Boot normally the underlying server (Tomcat, Jetty, Undertow) will listen for connections in the 0.0.0.0 address, i.e., in all the network interfaces available, including localhost. This is what troubles me, because as indicated, the service should be accessible through all the IPs in the machine.
In any way, I think you can try several things to solve your issue.
Probably the best approach to solve the problem will be to configure the hostname of your Eureka server and/or your Eureka clients to a common one.
For example, you can configure your server and clients to be exposed as localhost.
For that purpose, you need to include the following configuration property in their respective config files:
eureka:
instance:
hostname: localhost
Looks like you are using Docker. You are trying to connect to localhost but other services are running in other container hence localhost won’t work. Would you please try 0.0.0.0 or host.docker.internal in your YAML file and see if that will work.
In other words you will need to edit following.
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
or change EUREKA_URI env variable to reflect that. Also in your service YAML
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka/}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1

Get the hostname/IP:port of the server to which the request is to be forwarded from Zuul+ribbon

I'm using Eureka for service discovery and Zuul+ribbon as reverse proxy and load balancer.
I have 2 instances registered under Eureka as follows:
MYSERVICE n/a (2) (2) UP (2) - MYHOST:MyService:8888 , MYHOST:MyService:9999
Below is my zuul config:
#EnableZuulProxy
#EnableDiscoveryClient
zuul:
debug.request: true
sensitiveHeaders:
routes:
ecm:
path: /myservice/**
serviceId: MYSERVICE
stripPrefix: false
host:
maxTotalConnections: 200
maxPerRouteConnections: 30
RibbonRoutingFilter:
route.disable: false
I want a filter or interceptor which would help me log my request URL, my request params and the server chosen by Zuul.
I tried extending the following:
#Component
public class RibbonInterceptor extends ZoneAvoidanceRule {
#Override
public Server choose(Object key) {
Server choose = super.choose(key);
System.out.println(choose);
return choose;
}
But, this just gave me the server info from Ribbon, and here ribbon was just choosing a server. I wanted this info from Zuul along with the request details.
Please help!!
For the request URL and the server chosen by Zuul, you can set the loglevel of the LoadBalancerContext to DEBUG in application.properties.
#logging load balancing information
logging.level.com.netflix.loadbalancer.LoadBalancerContext=DEBUG
This will create a log statement like:
2017-09-11T12:59:09.746-07:00: [DEBUG] hystrix-myserviceV3-2 com.netflix.loadbalancer.LoadBalancerContext - myserviceV3 using LB returned Server: myservice-2.abc.com:8080 for request http:///myservice/auth/users
Not sure though, how you can handle the request params.
Assuming you use Apache HttpClient, there are many ways to do this but I think the most simple is to add an HttpRequestInterceptor to the CloseableHttpClient used by Ribbon. You can customize the client by providing a bean of type CloseableHttpClient as mentioned in the documentation [1]. You then have the request actually used by HttpClient so you log the details.
#Bean
public HttpClient delegate(IClientConfig clientConfig)
{
HttpClientBuilder builder = HttpClientBuilder.create();
//set connection pool configuration
HttpRequestInterceptor interceptor = (request, context) -> logger.info("Server : {}, headers : {}", request.getRequestLine().getUri(), request.getAllHeaders());
builder.addInterceptorFirst(interceptor);
return builder.build();
}
You could also extend HttpClientRibbonCommand and override the run() method to print what you want. You would use your new class by providing a bean of type RibbonCommandFactory<YourExtendedRibbonCommand> and it should wire automatically to the RibbonRoutingFilter.
Finally, if you're using the semaphore isolation strategy in hystrix, you could use your RibbonInterceptor like you indeed in addition to com.netflix.zuul.context.RequestContext. In the RequestContext, you'll find the original HttpServletRequest along with parsed parameters and headers that were processed in the pre filters.
[1] https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_zuul_http_client

spring /oauth/token, AuthorizationFailureEvent -> AuthenticationSuccessEvent

Spring Boot 2, OAuth2, and I use InMemoryTokenStore.
I have defined the following setting:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
...
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.anyRequest().permitAll();
;
}
...
}
To get a token I'm making the following request:
curl Standard:Login#localhost:8080/oauth/token -d grant_type=password -d username=user -d password=passUser
Next, the following event chain occurs:
1) The first event raised is AuthorizationFailureEvent:
principal = anonymousUser
configAttributes = [fullyAuthenticated]
details = org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null
exceptionClass = AccessDeniedException
source = FilterInvocation: URL: /oauth/token?username=user&password=passUser&grant_type=password
authorities = [ROLE_ANONYMOUS]
exceptionMessage = Access is denied
timestamp = 2017-12-01 14:45:34
2) Then AuthenticationSuccessEvent:
details = remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>
source = org.springframework.security.oauth2.provider.OAuth2Authentication#eb5a2d91: Principal: {
"id":" user",
"password": "****",
"authorities": ["USER"],
"firstName": "",
"lastName": "",
"accountNonExpired": "true",
"credentialsNonExpired": "true",
"accountNonLocked": "true",
"enabled": "true"
}; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>; Granted Authorities: "USER"
timestamp = 2017-12-01 14:45:36
3) And finally the server successfully returns a token:
{
"access_token" : "2d37dd06-0f35-441f-a851-96d145836eed",
"token_type" : "bearer",
"expires_in" : 863999,
"scope" : "all"
}
Please help me understand:
What settings should I make so that event AuthorizationFailureEvent does not occur?

Spring Websocket url hits RequestMapping but not MessageMapping

I'm having trouble setting up a websocket configuration in an existing web application.
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/mobile");
config.setApplicationDestinationPrefixes("/mobile-server");
config.setUserDestinationPrefix("/mobile-user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/mobile-socket")
.withSockJS()
.setInterceptors(new HttpSessionHandshakeInterceptor());
}
}
Controller
#Controller
public class WebSocketInboxController{
#MessageMapping("/inbox")
#SendToUser("/mobile")
public Map<String,Object> inbox(
){
Map<String,Object> res = new HashMap<>();
res.put("hello", "hello");
return res;
}
client
const webstomp = require('webstomp-client');
const socket = webstomp.client('ws://www.dev.server.com/mobile-socket',{
debug:true
});
socket.connect('marc#gmail.com', '123456', (client) => {
console.log('connected');
socket.send("/mobile-server/inbox",)
socket.subscribe("/mobile/inbox");
}, (client, err) => {
console.log(err);
});
What I see when the client tries to connect is spring trying to match the /mobile-socket against the RequestMappings of the existing web application, finally hitting one that matches it by way of a #RequestMapping("/{somevar}").
I'm new to WebSockets, but I would expect the endpoint registration be a catchall for these kinds of connects?
Even after removing the erronous RequestMapping being hit, I can't seem to get the MessageMapping to be hit. I see this in my log
AntPathRequestMatcher.matches(150) | Request '/mobile-socket' matched by universal pattern '/**'
[MSA] DEBUG [2016-06-03T11:16:21,025] FilterSecurityInterceptor.beforeInvocation(219) | Secure object: FilterInvocation: URL: /mobile-socket; Attributes: [permitAll]
[MSA] DEBUG [2016-06-03T11:16:21,025] FilterSecurityInterceptor.authenticateIfRequired(348) | Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
[MSA] DEBUG [2016-06-03T11:16:21,025] AffirmativeBased.decide(66) | Voter: org.springframework.security.web.access.expression.WebExpressionVoter#444af45, returned: 1
[MSA] DEBUG [2016-06-03T11:16:21,025] FilterSecurityInterceptor.beforeInvocation(243) | Authorization successful
[MSA] DEBUG [2016-06-03T11:16:21,026] FilterSecurityInterceptor.beforeInvocation(256) | RunAsManager did not change Authentication object
[MSA] DEBUG [2016-06-03T11:16:21,026] FilterChainProxy.doFilter(325) | /mobile-socket at position 16 of 16 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
[MSA] DEBUG [2016-06-03T11:16:21,026] FilterChainProxy.doFilter(310) | /mobile-socket reached end of additional filter chain; proceeding with original chain
[MSA] DEBUG [2016-06-03T11:16:21,027] ExceptionTranslationFilter.doFilter(117) | Chain processed normally
[MSA] DEBUG [2016-06-03T11:16:21,027] HstsHeaderWriter.writeHeaders(130) | Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#53cc2afb
[MSA] DEBUG [2016-06-03T11:16:21,027] HttpSessionSecurityContextRepository.saveContext(352) | SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
[MSA] DEBUG [2016-06-03T11:16:21,028] SecurityContextPersistenceFilter.doFilter(120) | SecurityContextHolder now cleared, as request processing completed
The Spring tries to match the "/mobile-socket" against the RequestMappings because all the requests go to HandlerMapping beans in the web application context to map incoming web requests to appropriate handlers. With the introduction of annotated controllers, RequestMappingHandlerMapping automatically looks for #RequestMapping annotations on all #Controller beans including the controller which has #MessageMapping.
Since the #MessageMapping can only be defined under #Controller annotation, Spring would try to match other RequestMappings as well.
One possible solution could be to introduce interceptor to handle the websocket request url to specifically map to a particular controller. You can give it a try!

Spring Security pre-authentication - gives me a new session even though principal is unchanged

I have implemented a spring security preathentication filter in my Grails application in order to integrate with Tivoli Access Manager.
The filter getting called for every request in my web application - yet even though the filter returns the same principal as a previous request, it seems to create a new session. I have created a ApplicationListener to listen for authentication events and I can see a new AuthenticationSuccessEvent, with a new session id for each request.
This means all my session variables get cleared each request- which wouldn't be a big deal but it breaks the uploadr plugin.
When I turn debug logging on for my preauthentication filter I see that it thinks the principal has changed, even though it has not:
2015-03-04 11:34:57.769 foobar.TamAuthenticationFilter Checking secure context token: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken#f0666480: Principal: grails.plugin.springsecurity.userdetails.GrailsUser#3125618: Username: 66734; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_APPROVER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffde5d4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 87928D9E25D98DD3CCFAC5D67689E609; Granted Authorities: ROLE_ADMIN, ROLE_APPROVER
2015-03-04 11:34:57.770 foobar.TamAuthenticationFilter Pre-authenticated principal has changed to 66734 and will be reauthenticated
2015-03-04 11:34:57.770 foobar.TamAuthenticationFilter Invalidating existing session
2015-03-04 11:34:57.771 foobar.TamAuthenticationFilter preAuthenticatedPrincipal = 66734, trying to authenticate
How can I make spring security use the same session for each principal returned by the pre authentication filter, rather than create a new one for every request?
here is my filter:
package foobar
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter
import grails.util.Environment
import grails.util.Holders
import groovy.util.logging.Log4j
#Log4j
class TamAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
java.lang.Object getPreAuthenticatedCredentials(javax.servlet.http.HttpServletRequest request)
{
"N/A"
}
java.lang.Object getPreAuthenticatedPrincipal(javax.servlet.http.HttpServletRequest request)
{
Long staffId = getStaffIdFromTamHeader(request)
if(!staffId)
log.error "iv-user header not found"
return staffId
}
/**
* Get Staff ID from the ivUser Tamheader.
* #param request
* #return
*/
static public Long getStaffIdFromTamHeader(request) {
return request.getHeader("iv-user")
}
}
LoggingSecurityEventListener:
package foobar
import groovy.util.logging.Log4j
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event.AbstractAuthenticationEvent
#Log4j
class LoggingSecurityEventListener implements
ApplicationListener<AbstractAuthenticationEvent> {
void onApplicationEvent(AbstractAuthenticationEvent event) {
def username = event.authentication.principal
def address = event.authentication.details.remoteAddress
def sessionId = event.authentication.details.sessionId
log.info "event=${event.class.simpleName} username=${username} remoteAddress=${address} sessionId=${sessionId}"
}
}
resources.groovy:
beans = {
//
// grabs the user id from the tam headers
//
tamAuthenticationFilter(TamAuthenticationFilter) {
authenticationManager = ref('authenticationManager')
checkForPrincipalChanges = true
}
tamAuthenticationProvider(PreAuthenticatedAuthenticationProvider) {
preAuthenticatedUserDetailsService = ref('authenticationUserDetailsService')
}
//
// we do not want to redirect to the auth/login page since we are using tam
//
authenticationEntryPoint(Http403ForbiddenEntryPoint)
securityEventListener(LoggingSecurityEventListener)
}
config.groovy:
grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.providerNames = ['tamAuthenticationProvider']
grails.plugin.springsecurity.userLookup.userDomainClassName = 'strobe.auth.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'strobe.auth.UserRole'
grails.plugin.springsecurity.authority.className = 'strobe.auth.Role'
grails.plugin.springsecurity.securityConfigType="InterceptUrlMap"
grails.plugin.springsecurity.interceptUrlMap = [
'/foobar/**': ['ROLE_USER']]
bootstrap.groovy:
def init = { servletContext -> SpringSecurityUtils.clientRegisterFilter('tamAuthenticationFilter',
SecurityFilterPosition.PRE_AUTH_FILTER.order + 10)
}
I have found the solution to my problem- I was returning a Long from getPreauthenticatedPrincipal() which confuses spring security, as the method requiresAuthentication() in AbstractPreauthenticatedProcessingFilter has this line of code:
if ((principal instanceof String) && currentUser.getName().equals(principal)) {
return false;
}
It expects the principal to be a String. Every time I returned a long it would reauthenticate and give me a new session.
I can't believe the solution was that simple and it took me 2 days to figure out!!!
Part of the problem I think is the scant documentation on preauthentication in spring and also the method signature of:
java.lang.Object getPreAuthenticatedPrincipal(javax.servlet.http.HttpServletRequest request)
which doesn't clearly suggest a return type.

Resources