spring integration : response message not sent to client from error-channel - response

I've the understanding that Spring Integration (SI) will wrap any exception (under the SI domain) to a MessageException instance and place it on the "error-channel".
Following are few snippets from my spring config file :
<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="1">
<bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgJSONSyntaxValidationInterceptor"/>
</int:channel-interceptor>
<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="2">
<bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgMetaDataValidationInterceptor"/>
</int:channel-interceptor>
<!-- Gateways -->
<int:gateway id="ersServiceReqRcvGateway"
service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcReqGateway"
error-channel="reqRcvExceptionHandlerChannel">
<int:method name="processRequest" request-channel="ersServiceReqRcvPostValidationChannel" />
</int:gateway>
<!-- Chain to handle all incoming request *after* doing all validations -->
<int:chain input-channel="ersServiceReqRcvPostValidationChannel">
<int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
<!-- Router -->
<int:router ref="ersServiceReqRcvRouter" />
</int:chain>
<!-- 6) Pass the message through ERS svc to Exec svc ADH chain - Chain2 -->
<int:chain input-channel="ersSvc2execSvcQMRChannel" output-channel="ersServiceResRcvPostValidationChannel">
<int:transformer ref="json2ObjTransformer" method="transformToERSOrchestrationSvcReq" />
<int:service-activator ref="executionSvcReqMsgBuilder" method="getRptExecutionSvcReqForDataEngine" />
<int:transformer ref="obj2JsonTransformer" method="transformFromRptExecutionSvcReqForDataEngine" />
<int:service-activator ref="msgReqAuditDAOIntegrator" method="persist" />
<int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
<int:service-activator ref="executionSvcRESTStub" method="executeReportJSON" />
</int:chain>
<int:chain input-channel="reqRcvExceptionHandlerChannel">
<int:transformer ref="exceptionTransformer" method="handleError"/>
</int:chain>
The client makes a REST call to my implementation class which inturn places the received request on the Gateway defined in above spring config file
#Path("/reportExecutor")
public class ERSOrchestrationServiceImpl {
#Autowired
private ReportInstanceDAO reportInstanceDAO;
private static final ERSOrchestrationSvcDiagnosticLogger _logger =
ERSOrchestrationSvcDiagnosticLogger.getInstance(ERSOrchestrationServiceImpl.class);
#Context
HttpServletRequest request;
#Context
HttpServletResponse response;
#POST
#Path("/executeOnlineReport")
#Produces({MediaType.APPLICATION_JSON})
public String executeOnlineReport(String jsonRequest) {
ApplicationContext appCtx = SpringApplicationContextUtil.getApplicationContext();
ERSOrchestrationSvcReqGateway ersOrchestrationSvcReqGateway =
(ERSOrchestrationSvcReqGateway) appCtx.getBean("ersServiceReqRcvGateway");
Message<String> inputMsg = MessageBuilder.withPayload(jsonRequest)
.setHeader(ERSServiceConstants.KEY_MSG_CORRELATION_ID, correlationId)
.setHeader(ERSServiceConstants.KEY_MSG_REPORT_INSTANCE_ID, reportInstanceId)
.build();
Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);
return returnMsg.getPayload();
}
As mentioned in above spring config file, the error-channel is read by a Transformer that creates a valid failed response message for the client and returns the message.
public class ErrorMessageUnwrapTransformer {
#Autowired
private Gson gsonUtil;
#Autowired
private ReportInstanceDAO reportInstanceDAO;
#Autowired
private ERSOrchestrationSvcFailedResMsgBuilder executionSvcFailedMsgBuilder;
private static final ERSOrchestrationSvcDiagnosticLogger _log =
ERSOrchestrationSvcDiagnosticLogger.getInstance(ErrorMessageUnwrapTransformer.class);
#Transformer
public Message<?> handleError(Message<?> message) {
try{
failedMsg = ((MessagingException) message.getPayload()).getFailedMessage();
//some code logic to build a valid failed response message goes here
Message<?> failedResponseMsg = executionSvcFailedMsgBuilder.getERSOrcSvcFailedResMsg(failedMsg );
return failedResponseMsg;
}
All seems to work fine when I get an exception, i.e., the exception is wrapped as MessagingException, put on the error-channel, the Transformer is able to read the channel, get failedMessage out of it, able to create a valid failed response message and return it.
However, the only issue I get is the call does not go back to the caller. In other words, the handle does not go back to the following code that had initiated the processing flow:
Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);
Can someone pls let me know why is the message returned by error-channel-read-Transformer not returning back to the class that invoked the Gateway method ?

Your problem here that you return the entire Message<?> from the transformer. This one is a component which doesn't care about headers, when the returned object is Message<?> already. You should worry about them on your own, like copy all headers from the failedMsg to your own failedResponseMsg.
Why is that so important?
Since you use request/reply gateway you are expecting for the return on that method invocation, something on the background ensure that for you. And it is a classical replyChannel algorithm.
Any AbstractReplyProducingMessageHandler sends its result to the replyChannel, if you don't have an outputChannel configured, like your reqRcvExceptionHandlerChannel <chain> here.
With other components we can rely on the copy-header-from-request function, but not here with the <transformer>.
From other side ErrorMessage may be created in some context where we don't have headers, but we exactly may have the failedMessage in the MessagingException for which the ErrorMessage has been caused. So, we have to ensure headers from that failedMessage.
Hope I am clear.

Related

Is it possible to validate a JWT token created from an external OAuth2 Server in WSO2?

I have a Spring Security OAuth2 server that generates JWT tokens for frontend applications.
This tokens will be sent in the calls to the backends, passing through an API Gateway (WSO2 API Manager).
What I would like is to have the backend APIs registered in WSO2 and be able to validate that externally generated JWT token.
Is this possible? Can you provide a sample of the different places of the WSO2 APIM that would need to be configured to include this logic?
NOTICE: The WSO2 will never need to create the token, it'll always have been created previously, it only needs to validate it.
After a lot of trial and error and some help from Stackoverflow (kudos to Bee) this is my working solution. I hope it helps others since it was really tricky to make it work:
1. Implement a JWTAuthHandler to validate the JWT tokens:
public class JwtAuthHandler extends AbstractHandler {
private final PublicKeyFactory pkf = new PublicKeyFactory();
private final JwtVerifier jwtVerifier = new JwtVerifier();
#Override
public boolean handleRequest(MessageContext messageContext) {
try {
final String jwtToken = getJwtTokenFromHeaders(messageContext).replace("Bearer ", "");
SignedJWT signedJwt = SignedJWT.parse(jwtToken);
final JSONObject payload = signedJwt.getPayload().toJSONObject();
final JSONObject environment = (JSONObject)payload.get("environment");
PublicKey publicKey = readPublicKey();
JWSVerifier verifier = new RSASSAVerifier(((RSAPublicKey) publicKey));
final boolean signatureVerification = signedJwt.verify(verifier)
if (signatureVerification) {
AuthenticationContext authContext = new AuthenticationContext();
authContext.setAuthenticated(true);
if (isProductionRequest(environment)) {
authContext.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION);
} else {
authContext.setKeyType(APIConstants.API_KEY_TYPE_SANDBOX);
}
APISecurityUtils.setAuthenticationContext(messageContext, authContext, "Authorization");
} else {
LOG.debug("handleRequest() - Sending 401 Unauthorized");
Utils.sendFault(messageContext, 401);
}
return signatureVerification;
} catch (Exception e) {
e.printStackTrace();
Utils.sendFault(messageContext, 500);
return false;
}
}
#Override
public boolean handleResponse(MessageContext messageContext) {
return true;
}
private String getJwtTokenFromHeaders(MessageContext messageContext) {
Map headers = (Map) ((Axis2MessageContext) messageContext).getAxis2MessageContext().
getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
return (String) headers.get("Authorization");
}
private boolean isProductionRequest(JSONObject environment) {
return environment != null && environment.equals("pro");
}
}
2. Override your API definition (/repository/deployment/server/synapse-configs/default/api/yourapi.xml) to use the jwt handler and remove the APIAuthenticationHandler and the ThrottleHandler (the latter needs to be removed because of a well known bug for non-oauth2-authenticated apis):
It should have something like this:
<handlers>
<handler class="com.codependent.JwtAuthHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.common.APIMgtLatencyStatsHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.CORSRequestHandler">
<property name="apiImplementationType" value="ENDPOINT"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtUsageHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.analytics.APIMgtGoogleAnalyticsTrackingHandler">
<property name="configKey" value="gov:/apimgt/statistics/ga-config.xml"/>
</handler>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerExtensionHandler"/>
</handlers>
IMPORTANT:
The processing backend is usually derived (in normal OAuth2 requests) from the OAuth2 access token. Since here we replaced it, WSO2 can't determine which environment to invoke so it'll call PRODUCTION as default. To work around this, insert some extra field in your JWT, in my case environment, that helps you decide. Then, create an AuthenticationContext with the appropiate environment as shown. That's it!
If you directly edit yourapi.xml descriptor it'll be replaced the next time you publish it. To automate its generation edit the velocity template (/repository/resources/api_templates/velocity_template.xml). In my case I only want it to apply to some applications, so I use a tag (jwt-auth) to select them.
velocity_template.xml:
<handlers xmlns="http://ws.apache.org/ns/synapse">
#if($apiObj.tags.contains("jwt-auth"))
<handler class="com.codependent.JwtAuthHandler"/>
#end
#foreach($handler in $handlers)
#if((($handler.className != "org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler") &&
($handler.className != "org.wso2.carbon.apimgt.gateway.handlers.throttling.ThrottleHandler")) ||
!($apiObj.tags.contains("jwt-auth")))
<handler xmlns="http://ws.apache.org/ns/synapse" class="$handler.className">
#if($handler.hasProperties())
#set ($map = $handler.getProperties() )
#foreach($property in $map.entrySet())
<property name="$!property.key" value="$!property.value"/>
#end
#end
</handler>
#end
#end
</handlers>
Indeed you could write a custom handler to authenticate on your own (basic authentication, jwt bearer). Good job finding that quickly. Maybe as an improvement you could cache the validated jwt token (or jwt hash) as the validation may take some time and performance.
As a default solution (without any customization) you could use JWT grant
exchanging a token from a trusted IdP for an internal APIM token.

Spring OAuth2 - There is no client authentication. Try adding an appropriate authentication filter

We have an application which is using spring-security-oauth2:1.0. I was trying to change it to a newer version, spring-security-oauth2:2.0.7.RELEASE. Some classes were removed, some package structure is changed, I managed to sort out all those things and I was able to start the server without any issue. But I am facing a strange issue here.
With OAuth2 - 1.0 version, when the user logs in we used to do a GET request on /oauth/token, For example :
http://localhost:8080/echo/oauth/token?grant_type=password&client_id=ws&client_secret=secret&scope=read,write&username=john#abc.com&password=password123
and It used to work just fine.
When I try the same thing, First of all I am not able to make a GET request because of the logic in TokenEndPoint.java
private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST));
#RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, #RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!allowedRequestMethods.contains(HttpMethod.GET)) {
throw new HttpRequestMethodNotSupportedException("GET");
}
return postAccessToken(principal, parameters);
}
I have tried to make a POST request same as above URL, but I get InsufficientAuthenticationException with the error message
There is no client authentication. Try adding an appropriate authentication filter
This is because of the following POST request controller in TokenEndpoint.java. When I debug, I see that principal is null.
#RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, #RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
//principal is null here
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
.............
}
I have an authentication filter and it worked well when I used version 1.0. This is the relevant prats of my config:
<authentication-manager xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="userDetailsService"/>
</authentication-manager>
<bean id="userDetailsService" class="com.hcl.nc.service.UserDetailsService">
<constructor-arg><ref bean="sessionFactory" /></constructor-arg>
</bean>
I always thought that the request will be authenticated by authentication-provider and goes to token-endpoint but that does not seem to be the correct flow. After debugging the application with version 2.0.7, now I really doubt my understanding about the flow.
Could somebody please explain why it worked in previous version and why it's not working now?
Do I have do to something different to get a OAuth token??
NOTE: I have already checked these questions : here, here, here. But I was not able to find the correct solution.
I don't know the previous version, but I know a bit about 2.0.7.
I suspect your problem is that your TokenEndpoint security tries to authenticate your clients against your user service.
The TokenEndpoint is protected by a BasicAuthenticationFilter. By default this filter would use an AuthenticationManager instance, which itself holds an AuthenticationProvider, which itself depends on an instance of UserDetailsService.
The trick is that this particular instance of UserDetailsService must be client based, not user based : that's why there is a ClientDetailsUserDetailsService, which adapts ClientDetailsService to UserDetailsService.
Normally all this stuff is already done by default when you use the framework's configuration classes AuthorizationServerConfigurerAdapter, #EnableAuthorizationServer, etc..
I had the same problem and my application.yml had this line:
servlet:
path: /auth
so the token address was: /auth/oauth/token
I remove the path from application.yml so the token path became:
/oauth/token
And everything works fine.
I hope this help
One of the problems of the following error, can be that authentication was not performed. I have encountered this problem with older implementation of Spring.
verify that:
TokenEndpoint -> postAccessToken method. Check if Principal is not null. If it is null it means that Basic Authroziation was not performed.
One of the solution to add filter was to use:
#Configuration
public class FilterChainInitializer extends AbstractSecurityWebApplicationInitializer {
}
More information about AbstractSecurityWebApplicationInitializer can be found in Spring docs
The problem can be because of opening all requests. You should remove it.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/**");
}
in my case, i found this config:
security.allowFormAuthenticationForClients(); // here
then post this
http://localhost:8081/sso/oauth/token?client_id=unity-client&client_secret=unity&grant_type=authorization_code&code=Yk4Sum&redirect_uri=http://localhost:8082/sso-demo/passport/login
its works for me, try it
#Configuration
#EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(Oauth2Config.class);
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients(); // here
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { // #formatter:off
clients.inMemory()
.withClient("unity-client")
.secret("unity")
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
.scopes("foo", "read", "write")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(2592000) // 30 days
;
} // #formatter:on
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
}
I am following this tutorial - Practical Guide to Building an API Back End with Spring Boot'. See https://www.infoq.com/minibooks/spring-boot-building-api-backend , But with the latest SpringBoot Version(2.7)
and I run into this problem:
org.springframework.security.authentication.InsufficientAuthenticationException: There is no client authentication. Try adding an appropriate authentication filter. at org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(TokenEndpoint.java:91) ~[spring-security-oauth2-2.3.5.RELEASE.jar:na]
My solution/fix was to annotate WebSecurityGlobalConfig with #EnableWebSecurity because in the original course this annotation was missing.
So adding this annotaiton has fixed the error for me.

Does AOP with AspectJ works with method from Managed Bean called from the view in JSF2?

I’m currently facing a Problem using a combination of JSF 2 and AOP with AspectJ annotation.
I don't know if Spring AOP is playing a role here...(I didn't well understand difference between SPRING AOP, ASPECTJ, GOOGLE GUICE...that's an another question)
I'm trying to send an e-mail after i added some values in my database via click on a form in jsf view.
I have a managedBean AddPartipant handled by JSF (linked to a view) to add participant via a form. I want to intercept the method who makes the change in database and send an email just after this action.
I have a spring bean SendMailBoImpl with a method to send an email.(sending works ok)
I found using a AOP was a good way. It's works only when i trying to make it works in a main...not in the complete webapp. I read some stuffs about problem context spring / Jsf but don't found a solution...yet...
I know my method to add data in the database via the view is ok...but the mail is never sent whereas the database is modified.
Somebody has an idea ?
Thanks a lot :)
AddParticipant ManagedBean :
public class AddParticipant implements Serializable{
//DI via Spring
ParticipantBo participantBo;
private String id_study ;
private Participant aParticipant = new Participant();
//getters and setters
public void addParticipant(){
aParticipant.setId_study (id_study);
...
participantBo.save(aParticipant);
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Ajout du participant "+id_study+" dans l'étude "+ study_name));
}
MaiBo Service :
#After("execution(* com.clb.genomic.lyon.beans.AddParticipant.addParticipant(..))")
public void sendMail() {
....
mailSender.send(message);
....
}
My bean config :
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="addParticipant" class="com.clb.genomic.lyon.beans.AddParticipant"/>
<bean id="sendMailBo" class="com.clb.genomic.lyon.bo.SendMailBoImpl">
<property name="mailSender" ref="mailSender" />
<property name="simpleMailMessage" ref="customeMailMessage" />
</bean>
When i do this it's working :
ApplicationContext appContext = new ClassPathXmlApplicationContext
( "classpath:webConfiguration/applicationContext.xml");
AddParticipant aspect = (AddParticipant) appContext.getBean("addParticipant");
aspect.addParticipant();
Solved base on the read of this : http://kumarnvm.blogspot.fr/2012/07/using-spring-to-manage-jsf-september-10_14.html

JSF exception handling, get request param

i followed instructions from for implementing exception handling in jsf web app.
my problem is to show attribute value, that i set in ExceptionHandler
here is ExceptionHandler.java
#Override
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
while (i.hasNext()) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable t = context.getException();
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
NavigationHandler nav = fc.getApplication().getNavigationHandler();
try {
// Push some useful stuff to the request scope for
// use in the page
System.err.println("DefaultExceptionHandler.handle()...exceptionMessage = " + t.getMessage());
requestMap.put("exceptionMessage", t.getMessage());
nav.handleNavigation(fc, null, "error/500");
fc.renderResponse();
} finally {
i.remove();
}
}
getWrapped().handle();
}
and 500.xhtml
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core">
The error message is:
<br />
<b>
3. : #{exceptionMessage}
</b>
<br />
<b>
1. : #{requestScope['exceptionMessage']}
</b>
<br />
<b>
2. : #{param['exceptionMessage']}
</b>
and page in browser looks like:
The error message is:
3. :
1. :
2. :
thanks in advance!!
First of all, that's not a request parameter at all. Request parameters are the data which the enduser has sent to the server along with the HTTP request. In GET requests they are visible in query string part of the URL. In POST requests, they are hidden in request body (but visible with a HTTP traffic monitor such as browser's builtin one accessible by F12 key). What you were setting is a request attribute. So, from the attempts, only #{exceptionMessage} and #{requestScope['exceptionMessage']} should have worked, but #{param['exceptionMessage']} definitely not.
Coming back to your concrete problem, this can happen when you're sending a redirect on navigation by either <redirect> in navigation case, or by appending ?faces-redirect=true to the outcome somewhere in a custom navigation handler. A redirect basically instructs the client to create a brand new HTTP request, hereby trashing the initial HTTP request including all of its attributes.
If that's also not the problem, then the (customized) FacesContext or ExternalContext implementation being used is likely broken. Hard to tell as you didn't tell anything about the JSF impl/version used nor about the server used nor any "3rd party" libraries. E.g. Spring Web Flow's ExternalContext implementation is known to be broken like that in some versions.

Exception when saving securityContext to SecurityContextRepository

Started to secure some of my resful server resources using Spring Security.
My client is using ajax (jquery ajax) for the requests and I started by implementing the login functionality.
My Jersey web layer includes the following:
#Path("/login")
#Component
public class LoginResourceProvider extends ServiceResourceProvider {
/*--- Static ---*/
private final static ILogger logger = LogManager.getLogger(LoginResourceProvider.class);
/*--- Members ---*/
#Inject
#Qualifier("authenticationManager")
protected AuthenticationManager authenticationManager;
#Inject
protected SecurityContextRepository repository;
#Inject
protected RememberMeServices rememberMeServices;
/*--- Constructors ---*/
public LoginResourceProvider() {
super("Login");
}
/*--- Public Methods ---*/
#GET
public void login() {
}
/**
* A user login attempt
*
* #param username
* The user name
* #param password
* The password of the given user name
* #param request
* #param response
* #return A JSON string, indicating if the login is successful
*/
#POST
#Produces(MediaType.APPLICATION_JSON)
public String performLogin(#QueryParam("j_username") String username, #QueryParam("j_password") String password,
#Context HttpServletRequest request, #Context HttpServletResponse response) {
// Create a token
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
SecurityContext securityContext = SecurityContextHolder.getContext();
try {
// Attempting to authenticate the user
Authentication auth = authenticationManager.authenticate(token);
// Updating the SecurityContext, which represents the user's
// secured, authenticated session
securityContext.setAuthentication(auth);
// If the user authenticates successfully then the authentication
// storing the security context in the HttpSession between requests
repository.saveContext(securityContext, request, response);
// object is passed to the remember-me service
rememberMeServices.loginSuccess(request, response, auth);
// Successfully authenticated
return "{\"status\": true}";
// Bad Credentials
} catch (BadCredentialsException ex) {
return "{\"status\": false, \"error\": \"Bad Credentials\"}";
}
}
}
My security-context.xml is pretty basic for now, just enough to test my the login process:
<http use-expressions="true">
<form-login />
<remember-me />
<intercept-url pattern="/**" access="permitAll" />
<intercept-url pattern="/secured/**" access="isAuthenticated()" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
I have 2 questions:
Is it a good practice? I mean, I could not find lot's of "non-auto" login for ajax style requests there.
I'm getting an exception when trying to save the security context to the SecurityContextRepository, in this line:
repository.saveContext(securityContext, request, response);
When I'm trying to log in using bob as username and bobspassword password the authentication goes smoothly but while debugging this specific line I'm jumping to a ClassCastException with the message:
$Proxy31 cannot be cast to org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper
Any help is appreciated!
Ok, I think I got it.
According to Spring documentation authentication is done using the following steps:
The username and password are obtained and combined into an instance of UsernamePasswordAuthenticationToken (an instance of the Authentication interface, which we saw earlier).
The token is passed to an instance of AuthenticationManager for validation.
The AuthenticationManager returns a fully populated Authentication instance onsuccessful authentication.
The security context is established by calling SecurityContextHolder.getContext().setAuthentication(...) , passing in the returned authentication object.
In addition to the above steps, I also tried to store the SecurityContext in between requests by saving it to the SecurityContextRepository.
The responsibility for storing the SecurityContext between requests should fall to the SecurityContextPersistenceFilter which in it's turn invokes this operation, so no need for me to do it manually, I guess I should only stick to the above 4 steps.
UPDATE: I guess I tried implementing on my own something that Spring-Security already implements for me. I do not recommend following this approach, Spring-Security offers a much more simple practice.

Resources