Why I can't read session attribute from portlet that is set in AutoLogin class - session

I try unsuccessful to access from my portlet the session attribute that I have set during the AutoLogin phase.
Setting attribute in AutoLogin class:
#Override
public String[] login(HttpServletRequest request, HttpServletResponse response) throws AutoLoginException {
request.getSession().setAttribute("My-Attribute-Key", "Hello World");
...
}
Access attribute from Portlet:
#Override
public void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
Object attribute = PortalUtil.getHttpServletRequest(renderRequest).getSession().getAttribute("My-Attribute-Key");
...
}

Take a look at Session Sharing on Liferay Wiki.

Related

Spring Boot - How to get an IP address when using AuthenticationFailureBadCredentialsEvent?

Please tell me how can I get IP address when using AuthenticationFailureBadCredentialsEvent ?
#Autowired
private LoginAttemptService loginAttemptService;
#EventListener
public void onAuthenticationFailure(AuthenticationFailureBadCredentialsEvent event) {
// How can I get the ip address here?
}
The option shown below does not work.
WebAuthenticationDetails auth = (WebAuthenticationDetails) event.getAuthentication();
auth.getRemoteAddress();
I would give a try two possible solutions (I have not tested them) based on the fact that javax.servlet.ServletRequest interface has information about the remote host.
1. Using AuthenticationFailureHandler:
The interface AuthenticationFailureHandler has a method onAuthenticationFailure​(HttpServletRequest, HttpServletResponse, AuthenticationException) that has the request javax.servlet.http.HttpServletRequest available.
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse res, AuthenticationException e) throws IOException, ServletException {
// implementation
}
}
2. Invoking RequestContextHolder:
This context holder is able to obtain request attributes containing the servlet request currently bound to the thread through the method currentRequestAttributes.
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
ServletRequest servletRequest = attributes.getRequest();

Pre-conditions within #RequestMapping method?

I don't know how to redirect user if they do not meet certain preconditions for a #RequestMapping.
I have a simple form that after completion sends the user to "/secondForm" which is unrelated to "/firstForm", how can I restrict access to "/secondForm", if first form has not been completed?
What makes this more difficult for me there is a controller in the middle.
firstForm --- (submit)---> emailController ----(redirect)----> secondForm
If you want to redirect a user to another page when certain conditions are met, you can use an interceptor. Example interceptor class:
#Component
public class RedirectInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) {
if (request.getRequestURI().contains("secondForm") && modelAndView.getModel().get("someBoolean") == false {
try {
response.sendRedirect("/firstForm");
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
}
}
And register it in configuration class:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
RedirectInterceptor redirectInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(redirectInterceptor);
}
}
If you prefer xml configuration over java then you can alternatively use this in your spring config xml:
<mvc:interceptors>
<bean id="redirectInterceptor" class="path.to.your.interceptor.RedirectInterceptor"/>
</mvc:interceptors>
Found an additional way:
Using FlashAttribute, by assigning before the redirect in emailController that sets a value.
In applicationController, by using an if statement if there isn't a FlashAttribute then redirect is called to the root of the application.

using servlet filter with session variable

I have created a Java web application using JSF 2.
When a user login to my application, I store his identifier in the session, so:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("userid", myBean.getUserId());
Then I created my filter:
public class PageFilter implements Filter {
private FilterConfig filterconfig;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterconfig = filterconfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httprequest =(HttpServletRequest) request;
HttpServletResponse httpresponse =(HttpServletResponse) response;
HttpSession session = ((HttpServletRequest) request).getSession();
String userid = (String) session.getAttribute("userid");
String pageRequested = httprequest.getRequestURI();
try {
if( userid != null && pageRequested.contains("index.xhtml") ) {
System.out.printf("User authenticated with " + httprequest.getRemoteUser() + " username conected.");
httprequest.getRequestDispatcher("/service/home.xhtml").forward(request, response);
} else {
chain.doFilter(request, response);
}
}catch(IOException | ServletException e){
//do something
}
}
#Override
public void destroy() {
System.out.print("Existing from loginFilter");
}
}
My scope is to manage the refresh button of the browser so if user is already logged then user is redirected to /service/home.xhtml. Also, the url in my web application is always:
localhost:8080/myapplication
So if user browses the site among all the pages, the url is always that (the action is hidden).
The problem is that if user clicks on the url in the browser, the request is for index.xhtml and my session is null (I cannot get user identifier by session.getAttribute("userid");).
Where is my fault?
The index.xhtml is defined as welcome-file-list in my web.xml:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
Thanks.

how to get returned value of my controllers from HandlerInterceptor

I'm creating a log manager for my controllers that logs every action in it and returned values
My controllers are defined in this way:
#Controller
#RequestMapping(value="/ajax/user")
public class UserController extends AbstractController{
#RequestMapping(value="/signup")
public #ResponseBody ActionResponse signup(#Valid SignupModel sign) {
ActionResponse response=new ActionRespone();
response.setMessage("This is a test message");
return response;
}
}
and I defined a HandlerInterceptor to log output of each handler:
#Component
public class ControllerInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
LogManager log=new LogManager();
log.setMessage();//I need returned ActionResponse here
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
where I use log.setMessage(); I need my ActionResponse's message (This is a test message) which is returned from signup method
How can I do this?
An interceptor is not the right place to do what you want since it's not capable of getting the return value of the handler.
You can achieve what you wan't without changing any existing code using aspect oriented programming (AOP). For this to work in spring you'll need to include the jars for spring-aop and AspectJ.
Creating the aspect and advice
#Aspect
#Component
public class ActionResponseLoggerAspect {
private static final Logger logger = LoggerFactory.getLogger(ActionResponseLoggerAspect.class);
#AfterReturning(pointcut="execution(* your.package.UserController.*(..)))", returning="result")
public void afterReturning(JoinPoint joinPoint , Object result) {
if (result instanceof ActionResponse) {
ActionResponse m = (ActionResponse) result;
logger.info("ActionResponse returned with message [{}]", m.getMessage());
}
}
}
The afterReturning method will be executed every time a controller method returns.
Enabling #AspectJ Support
Enable AspectJ support by adding this to your XML configuration.
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
For more info see the spring docs.

Spring Security authentication via URL

I have a Spring MVC app that uses Spring Security and form based login for authorization/authentication.
Now I want to add a special URL that includes a token that should be accessible without additional information because the token is unique to a user:
http://myserver.com/special/5f6be0c0-87d7-11e2-9e96-0800200c9a66/text.pdf
How do I need to configure Spring Security to use that token for user authentication?
You need to define your custom pre auth filter.
In security app context within http tag:
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthTokenFilter" />
Then define your filter bean (and its properties approprietly):
<beans:bean class="com.yourcompany.PreAuthTokenFilter"
id="preAuthTokenFilter">
<beans:property name="authenticationDetailsSource" ref="authenticationDetailsSource" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</beans:bean>
Create your custom filter extended from GenericFilterBean
public class PreAuthTokenFilter extends GenericFilterBean {
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String token = getTokenFromHeader(request);//your method
if (StringUtils.isNotEmpty(token)) {
/* get user entity from DB by token, retrieve its username and password*/
if (isUserTokenValid(/* some args */)) {
try {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication authResult = this.authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authResult);
} catch (AuthenticationException e) {
}
}
}
chain.doFilter(request, response);
}
/*
other methods
*/
If you don't want or cannot retrieve a password, you need to create your own AbstractAuthenticationToken which will receive only username as param (principal) and use it instead of UsernamePasswordAuthenticationToken:
public class PreAuthToken extends AbstractAuthenticationToken {
private final Object principal;
public PreAuthToken(Object principal) {
super(null);
super.setAuthenticated(true);
this.principal = principal;
}
#Override
public Object getCredentials() {
return "";
}
#Override
public Object getPrincipal() {
return principal;
}
}
You can provide a custom PreAuthenticatedProcessingFilter and PreAuthenticatedAuthenticationProvider. See Pre-Authentication Scenarios chapter for details.
I ran into this problem, and solved it using a custom implementation of the Spring Security RembereMe Service infrastructure. Here is what you need to do.
Define your own Authentication object
public class LinkAuthentication extends AbstractAuthenticationToken
{
#Override
public Object getCredentials()
{
return null;
}
#Override
public Object getPrincipal()
{
return the prncipal that that is passed in via the constructor
}
}
Define
public class LinkRememberMeService implements RememberMeServices, LogoutHandler
{
/**
* It might appear that once this method is called and returns an authentication object, that authentication should be finished and the
* request should proceed. However, spring security does not work that way.
*
* Once this method returns a non null authentication object, spring security still wants to run it through its authentication provider
* which, is totally brain dead on the part of Spring this, is why there is also a
* LinkAuthenticationProvider
*
*/
#Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response)
{
String accessUrl = ServletUtils.getApplicationUrl(request, "/special/");
String requestUrl = request.getRequestURL().toString();
if (requestUrl.startsWith(accessUrl))
{
// take appart the url extract the token, find the user details object
// and return it.
LinkAuthentication linkAuthentication = new LinkAuthentication(userDetailsInstance);
return linkAuthentication;
} else
{
return null;
}
}
#Override
public void loginFail(HttpServletRequest request, HttpServletResponse response)
{
}
#Override
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication)
{
}
#Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
{
}
}
public class LinkAuthenticationProvider implements AuthenticationProvider
{
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
// Spring Security is totally brain dead and over engineered
return authentication;
}
#Override
public boolean supports(Class<?> authentication)
{
return LinkAuthentication.class.isAssignableFrom(authentication);
}
}
Hack up the rest rest of your spring security xml to define a custom authentication provider, and the custom remember me service.
P.S. if you do base64 encoding of the GUID in your URL it will be a few characters shorter. You can use the Apache commons codec base64 binary encoder / decoder to do safer url links.
public static String toBase64Url(UUID uuid)
{
return Base64.encodeBase64URLSafeString(toBytes(uuid));
}

Resources