on 2017 Mar 09 6:09 PM
Whenever a backoffice user logs in, I would like to enrich their session with custom name/value-mappings (which I later would like to use within a Flexible Search query).
To be more precise, I have created a relationship between PointOfService
and Employee
. The relationship defines which point of services an employee is allowed to manage. My approach is to accumulate all point of services (POS) that are assigned to the employee as soon as they log in into backoffice. I would store the POS's PKs into the session and then add a Personalization rule that restricts the employee to the previously collected POSs.
My aim is to achieve this without modifying any stock code, that means I would like to rely solely on the features the Spring framework offers (Dependency injection, AOP) in order to keep my application modular and maintainable.
What I have done so far
1. Overriding behavior with beans/aliases
I found that the method(s) [Backoffice|ResetConfiguration]AuthenticationSuccessHandler.onAuthenticationSuccess()
are being called whenever a user logs in into backoffice. The instantiation is configured in backoffice/web/webroot/WEB-INF/lib/backoffice-core-[...].jar/META-INF/backoffice-core-spring-security.xml
. My first approach was to inject my code by overriding the [backoffice|resetConfiguration]AuthenticationSuccessHandler
beans.
However, as others have already reported I am unable to override the beans' definitions within my own custombackoffice-backoffice-spring.xml
; related topics below:
https://answers.sap.com/questions/12756517/define-a-different-success-handler-in-spring-secur-1.html
https://answers.sap.com/questions/12755552/cant-able-to-override-the-spring-security-configur.html
https://answers.sap.com/questions/12754623/backoffice-authentification.html ( here suggests to touch the core-spring-security.xml)
I strongly assume that the problem lies in the processing sequence: My bean/alias definition would have to be processed after the original bean definition and before their actual usage in <form-login [...] authentication-success-handler-ref="backofficeAuthenticationDetailsSource" [...]>
within the stock backoffice-spring-security.xml
. I guess that the regular process of merging spring.xml
files across all defined extensions does not apply in this context.
2. Using Spring AOP
Since I prefer not to touch any hybris stock code / configuration, my second approach was to use AOP to solve my problem. Within my custom backoffice-related extension custombackoffice
, I implemented an aspect that shall react to calls to com.hybris.cockpitng.util.web.authorization.BackofficeAuthenticationSuccessHandler.onAuthenticationSuccess
:
package my;
// ...
@Aspect
public class MyAspect {
private UserService userService;
@Around("execution(void com.hybris.cockpitng.util.web.authorization.ResetConfigurationAuthenticationSuccessHandler.onAuthenticationSuccess(..)) && args(request, response, authentication)")
public void myAdvice(ProceedingJoinPoint jp, HttpServletRequest req, HttpServletResponse res, final Authentication auth) throws Throwable {
// ...
jp.proceed();
// ...
EmployeeModel u = userService.getUserForUID(auth.getName(),
EmployeeModel.class); // #FAILING LINE#
// ...
request.getSession().setAttribute(...);
}
}
I configured AOP by creating an aop.xml
configuration file in custombackoffice/resources/META-INF
<aspectj>
<weaver options="-showWeaveInfo -verbose">
<include within="com.hybris.cockpitng.util.web.authorization..*" />
<include within="my..*" />
</weaver>
<aspects>
<aspect name="my.MyAspect" />
</aspects>
</aspectj>
and configured the aspect's bean in custombackoffice/resources/custombackoffice-spring.xml
:
<bean id="myAspect" class="my.MyAspect" factory-method="aspectOf">
<property name="userService" ref="userService" />
</bean>
However, when I let this configuration run I receive an exception:
java.lang.NullPointerException
at de.hybris.platform.servicelayer.session.impl.DefaultSessionService.executeInLocalView(DefaultSessionService.java:94)
at de.hybris.platform.servicelayer.search.impl.DefaultFlexibleSearchService.getJaloResult(DefaultFlexibleSearchService.java:396)
at de.hybris.platform.servicelayer.search.impl.DefaultFlexibleSearchService.search(DefaultFlexibleSearchService.java:168)
at de.hybris.platform.servicelayer.internal.dao.DefaultGenericDao.find(DefaultGenericDao.java:53)
at de.hybris.platform.servicelayer.user.daos.impl.DefaultUserDao.findUserByUID(DefaultUserDao.java:36)
at de.hybris.platform.servicelayer.user.impl.DefaultUserService.getUserForUID(DefaultUserService.java:90)
at de.hybris.platform.servicelayer.user.impl.DefaultUserService.getUserForUID(DefaultUserService.java:103)
at my.MyAspect.aspect(MyAspect.java:#FAILING LINE#)
The exception happens on the userService.getUserForUID
line due to DefaultSessionService.getOrCreateCurrentJaloSession()
returning null. While investigating this issue I found that services (including userService
) perform their operation on the junit tenant while my advice runs. Their field AbstractService.currentTenant
holds a reference to the junit tenant.
I then took a closer look on the server starting procedure which delivers following log (excerpt):
[PlatformInPlaceClassLoader@462b582b] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[...]
[PlatformInPlaceClassLoader@462b582b] info using configuration /C:/y-6.2/hybris/bin/custom/custombackoffice/resources/META-INF/aop.xml
[...]
[PlatformInPlaceClassLoader@462b582b] info register aspect my.MyAspect
[...]
[32mINFO [localhost-startStop-1] [TenantActivationAspect] Configured tenant <<master>> for aspect
[...]
[InnerLoader@3ced5597] info register aspect my.MyAspect
[32mINFO [localhost-startStop-1] (junit) [TenantActivationAspect] Configured tenant <<junit>>[327654167] for aspect
Noticeably, my aspect is being registered for both the master and junit tenant. My initial guess was that the advice is executed twice (one time for "master", the second time for "junit") but this is not the case. The advice is only executed in the junit tenant context.
Furthermore, I forced the hybris server to start without the junit tenant activated. I thus added
installed.tenants=
to my config/local.properties
configuration. This works!
3. Solving the problem with a different approach
Right now, I am going to tackle the problem by supplying overriden versions of the Default[User|Session]Service
services since this approach looks more promising and controllable to me.
However, I am still curious on how to successfully pursue my two initial approaches:
Is it possible to override beans that are referenced by the stock backoffice-spring-security.xml
only by means of Spring's dependency injection (that means without actually touching it)?
What is the deal with backoffice aspects? Why is the JUnit tenant being used instead of the master tenant? Could this actually be a bug?
Request clarification before answering.
Hi,
Please move your java file (custom file that extends backofficeAuthenticationSuccessHandler) in backoffice content i.e customBackoffice/backoffice/src folder. It should not be inside customBackoffice/src folder.
It worked for me. I was supposed to capture last login time of employee while he/she login into backoffice.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
1 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.