I am working on a Spring security project where if User inserts wrong userId - password, webpage will update with "Invalid Login Attempt" message.
I am sending redirect on AuthenticationFailureHandler.onAuthenticationFailure
code snippet for onAuthenticationFailure() implementation.
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
//some logic
response.sendRedirect(String.format("%s?error", getUrl());
}
}
Resource Html page has div tag with thymeleaf dependency to identify error object and display message
<div th:if="${error}" id="loginFailedMessage" class="alert alert-danger">
Invalid login attempt.
</div>
So far this implementation works on Jboss application server and WebLogic application server - however when not for websphere. Is there a reason why WebSphere is blocking such url invocation - any configuration am I missing. I have tired different version of WebSphere 8.5.5.9 up to 8.5.5.13
ps. there are no errors in any logs ffdc or application logs.
Solution will be to use error=true in url. for some reason websphere does not allow url parameter without assigning values.
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
//some logic
response.sendRedirect(String.format("%s?error=true", getUrl());
}
}
Related
I am using springboot 2.0.0.RELEASE, I just migrated from springboot 1.5.1
I have below code to filter bad login in springboot:
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
above code will filter the bad login and send error to frontend WEB client.
In springboot 1.5.1, the error in the response will contain JSON body, such as:
{"timestamp":1523253790780,"status":401,"error":"Unauthorized","message":"Autentication failed.","path":"/login"}
but when I use springboot 2.0, I can't get HTTP response, and I got error complain the error= null from the web client, I don't know where to look for the problem.
I use tomcat-embed 8.5.28 and jackson jar version for 2.9.4, if I remove above sendError, just use PrintWriter in response to add JSON string for myself, it works, so the issue i suppose is the sendError method not working for me in springboot 2.0.
thanks in advance.
I'm working with a Spring microservice protected with Spring Security SSO login (Using Cloudfoundry UAA).
Microservice when deployed on Cloud is accessible via HTTPS URL. Since HTTPS URL is of the ELB (Load balancer/web server), actual request to microservice from ELB comes on HTTP. So Spring when redirecting the user to login page produces HTTP URL instead of HTTPS URL in 302 Location header.
Following is the flow
Browser
->(https://mymicroservice.com) Unauthenticated request (Load balancer)
->(http://internal_lan_ip:someport) Microservice
-> 302 Location http://mymicroservice.com/login
-> Browser http://mymicroservice.com/login (failed)
In short it goes from HTTPS -> HTTP -> 302 HTTP (failed as ELB doesn't serve on HTTP)
Following is what I have tried
x-forwarded-proto
Since load balancer is also not populating x-forwarded-proto correctly to HTTPS, instead it gives me HTTP, I can't use Spring's support for it.
Require channel HTTPS
It also doesn't work, as it results in infinite redirections from Spring as Spring never receives an HTTPS request from ELB, despite correctly having produced HTTPS redirect URL.
Interceptor/Filter
Use a ServletFilter to check response header Location and if present replace http:// with https://.
Frankly last option is my final option as I do not control the ELB configuration.
Now issue is that I'm unable to intercept the response after spring redirects to /login URL which in turn should redirect to SSO URL.
I have tried various combinations of Interceptors (postHandle, afterCompletion), using Spring security to inject it at various locations in the filter chain and finally setting the filter order to lowest. None of these intercept unauthenticated request after redirection.
#Component
#Order(Ordered.LOWEST_PRECEDENCE)
class RedirectUrlProtocolUpdaterFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String locationHeader = response.getHeader("Location");
System.out.println("############ inside interceptor");
for(String name: response.getHeaderNames()) {
System.out.println(name + " : " + response.getHeader(name));
}
if(locationHeader != null && locationHeader.startsWith("http://")) {
System.out.println("###################### setting location header");
locationHeader = locationHeader.replaceAll("http://", "https://");
response.setHeader("Location", locationHeader);
}
filterChain.doFilter(request, response);
}
}
How do I correctly intercept the /login redirection by Spring Security in a filter/interceptor and update Location header to include correct protocol?
Any hint is appreciated.
If you want to update Location header info you can try to use an HttpResponseInterceptor.
This is an example of use from google HttpResponseInterceptor:
https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/http/HttpResponseInterceptor
Other option is from Apache:
https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/class-use/HttpResponseInterceptor.html
SpringFramework provides the HandlerInterceptor. This will intercept all http request, but can be used to constantly check for authentication and authorization. You will have to provide implementations for 3 methods (if you don't use them just implement an empty method). You can then put your code in the preHandle method.
public class AuthenticationInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
}
#Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
I have a Spring Mvc Application using hibernate hosted on ibm bluemix with domain registered in go daddy using tomcat server using the java_buildpack provided by blue mix for tomcat.Currently I have bought a ssl certificate in go daddy registered in blue mix.My application now works both on http and https.But now i have a requirement to enforce only https connection to my application .I implemented Spring Security .I have used Security config to enforce https and used below code for https redirection .
requiresChannel().anyRequest().requiresSecure()
but it gives me the following error in browser
Too many redirects occurred trying to open “https://website-name”. This might occur if you open a page that is redirected to open another page which then is redirected to open the original page.
Now I have followed few links over network inorder to enforce https where they told me to add few parameters I added these parameters in blue mix runtime environmental variables of my application.
server.tomcat.internal-proxies:.*
I also tried adding
server.tomcat.remote_ip_header:x-forwarded-for
server.tomcat.protocol_header:x-forwarded-proto
the flow of application is first go daddy lookup then it goes to the blue mix application how can i have only https enabled
But Still I get The Same error.
Guys can you help me solve this problem.
I added the custom filter
#Component
public class CustomFilter implements Filter {
private static final Logger logger = Logger.getLogger(CartController.class);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request1, ServletResponse response1, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) request1;
HttpServletResponse response = (HttpServletResponse) response1;
if (!request.isSecure()) {
logger.info("Not secure");
// generate full URL to https
StringBuilder newUrl = new StringBuilder("https://");
newUrl.append(request.getServerName());
if (request.getRequestURI() != null) {
newUrl.append(request.getRequestURI());
}
if (request.getQueryString() != null) {
newUrl.append("?").append(request.getQueryString());
}
response.sendRedirect(newUrl.toString());
} else {
// already a secure connection, no redirect to https required.
logger.info("Else");
if (chain != null) {
logger.info("Chain Null");
chain.doFilter(request, response);
}
}
}
}
I would advise two options:
1. In the past I have manually implemented a filter that if a non-http request is received to redirect to https. I have not used spring security in the manner you're attempting.
2. Post a question to Rob Winch, spring security lead, on the spring forms and cross link to this question so that people on the Bluemix platform can see his response.
My initial thought is that the manual filter is the way to go but would really like to know if Rob and team have encountered this on the CF platform.
Post on Liferay Forums: https://www.liferay.com/community/forums/-/message_boards/message/47412302
I have a simple application setup within a JSR-286 portlet to retrieve the value from a Portlet session.attribute
doView() method:
public void doView(RenderRequest renderRequest, RenderResponse renderResponse)
throws PortletException, IOException
{
renderResponse.setContentType("text/html");
getFormBean(renderRequest.getPortletSession());
PortletURL renderUrl = renderResponse.createRenderURL();
renderUrl.setWindowState(WindowState.MAXIMIZED);
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher(this.viewUrl);
dispatcher.include(renderRequest, renderResponse);
}
I set my attribute here in
TestPortlet.java:
private void getFormBean(PortletSession session)
{
String testVar = (String)session.getAttribute("testAttr", 1);
if (null == testVar) {
System.out.println("Setting Attribute inside Portlet");
session.setAttribute("testAttr", "TESTING SESSION", 1);
}
}
And retrieve the attribute here in TestServlet.java (same package):
private void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String testVal = (String) request.getSession(true).getAttribute("testAttr");
System.out.println("Test Attribute from Servlet:"+testVal);
}
The output of the application returns null
Setting Attribute in Portlet
Test Attribute from Servlet:null
Output should be:
Test Attribute from Servlet:TESTING SESSION
This application does work on my local setup, however not on a remote server with almost the same configurations.
I've included the javax-servlet-api-3.1.0 in my tomcat/lib to retrieve the HttpServletRequest Class, haven't found what else could be missing. I also haven't seen any Exceptions/ClassNotFound Errors.
Could there be any kind of server configuration that could interfere with the Session? (Authentication, network config, security)
Local setup
Tomcat 7.0.33
jdk-1.7 (compiled with 1.6 and 1.7)
Remote setup
Tomcat 7.0.33
Apache Web Server
jdk-1.6.0u35
more jar files in /lib (jdbc drivers, etc)
If you want to share session data between portlet and servlet in the same application (war), you have to place the attribute in the application scope, like this:
portletSession.setAttribute("testAttr", "TESTING SESSION", PortletSession.APPLICATION_SCOPE);
and then also retrieve it in portlet using scope:
portletSession.getAttribute("testAttr", PortletSession.APPLICATION_SCOPE);
I build a custom AuthenticationSuccessHandler so users can login using Ajax aswell use a normal login (for users with javascript disabled). To check if it's an ajax call or normal call I sent an extra request header.
If it is an Ajax call i want to return some different code as on normal request. This results needs to come from a jsp file. I could sent the url back but than the user have to do another request to get the data. How can i read the output of the jsp file from within my code or is this a bad design?
This is how i handle the request.
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) throws IOException,
ServletException{
if ("true".equals(request.getHeader("X-Ajax-call"))) {
response.getWriter().print("Output of jsp file should go here?");
response.getWriter().flush();
} else {
defaultHandler.onAuthenticationSuccess(request, response, auth);
}
}
Can't you simply forward the request:
request.getRequestDispatcher("myFile.jsp").forward(request, repsponse);