RESTful API authentication and further requests - java

I wrote a RESTful API in java in which the client has to create an account (POST to /user) and then login (POST to /login).
Now I am creating a frontend for the web-browser using AngularJS. The problem is, when I create a user, try to login and enter some login-secured-url's, I get
401 Unauthorized
It seems like every request should be authenticated separately, am I right ?
Steps I made:
POST to /user which creates a user
POST to /login which logs in the user
GET to /account/1/something which is login-secured path in my REST service, it returns 401
When I was writing the REST service, I was testing everything under RESTful WebService test-client in IntelliJ IDEA and it was and still is all right there.
What is the way to solve this problem ?
#Neo
Here you have RestAuthenticationSuccessHandler
#Component("successHandler")
public class RestAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RequestCache requestCache = new HttpSessionRequestCache();
#Override
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication)
throws ServletException, IOException {
final SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
clearAuthenticationAttributes(request);
return;
}
final String targetUrlParameter = getTargetUrlParameter();
if (isAlwaysUseDefaultTargetUrl() || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
requestCache.removeRequest(request, response);
clearAuthenticationAttributes(request);
return;
}
clearAuthenticationAttributes(request);
}
public void setRequestCache(final RequestCache requestCache) {
this.requestCache = requestCache;
}
}
I have also another classes, but the post would become too wordy if I added it all, so please let me know if you (suggesting a classname) need code of any of these below:

Related

How to restrict a user to access pages by typing the URL in the browser?

In My application I did java project with ajax calling here I have a problem without Login also user can type url accessing the pages for that I used the below code but when i add the below code it's not working. I am getting Page not found error even I am unable to getting a login page also.
#WebFilter("/*")
public class LoginFilters implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
private static final String AJAX_REDIRECT_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<partial-response><redirect url=\"%s\"></redirect></partial-response>";
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/Login.jsp";
boolean loggedIn = (session != null) && (session.getAttribute("Username") != null);
boolean loginRequest = request.getRequestURI().equals(loginURL);
boolean resourceRequest = request.getRequestURI().startsWith(request.getContextPath() + "/Login.jsp");
boolean ajaxRequest = "partial/ajax".equals(request.getHeader("Faces-Request"));
if (loggedIn || loginRequest || resourceRequest) {
if (!resourceRequest) { // Prevent browser from caching restricted resources. See also https://stackoverflow.com/q/4194207/157882
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response); // So, just continue request.
}
else if (ajaxRequest) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
response.getWriter().printf(AJAX_REDIRECT_XML, loginURL); // So, return special XML response instructing JSF ajax to send a redirect.
}
else {
response.sendRedirect(loginURL); // So, just perform standard synchronous redirect.
}
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
// ...
}
can anyone tell me how can i do this
You should take a look to this : Securing a Web Application
Securing a Web Application
This guide walks you through the process of creating a simple web
application with resources that are protected by Spring Security.
What you’ll build
You’ll build a Spring MVC application that secures the page with a
login form backed by a fixed list of users.
Spring is absolutely the best solution and I really recommend to use it: it helps you on everything! If you don't want to use it right now and you don't care about security too much you can roughly use a session token or a simple static token(even a boolean, a char or a string) that checks if the user is coming from a certain page or not:
if the code in a certain servlet(or in spring controller) is executed you should set this boolean-whateverYouWant field to a certain value: when you load a page you can check the value of that field(spring mvc-angularJs or javascript) and then you can show the right page: "Not Allowed" if the token is null or void or what you prefer!
The best and definitely solution would be spring security-angularJs and web services exposed in a spring mvc controller. Seriously... think about learning spring!

Redirect to desired location after login

I know this question can be found with different solutions. But I am unable to get it working in my project.
We are sending mails to users which has link to perform some action in the application. When user click on url he should be redirect to login page if he is not logged in and after login should be navigated to the targeted URL.
I am trying to fix using CustomLoginSuccessHandler here is the code.:
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
// public CustomLoginSuccessHandler(String defaultTargetUrl) {
// setDefaultTargetUrl(defaultTargetUrl);
// }
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
String redirectUrl = (String) session.getAttribute("url_prior_login");
if (redirectUrl != null) {
// we do not forget to clean this attribute from session
session.removeAttribute("url_prior_login");
// then we redirect
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
Configurations I am using are :
#Bean
public SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler(){
CustomLoginSuccessHandler successHandler = new CustomLoginSuccessHandler();
// SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
// successHandler.setUseReferer(true); getting NULL in the controller every time
// successHandler.setTargetUrlParameter("targetUrl"); this also doesnt work as browser is redirect to /login page and URL parameters are lost
return successHandler;
}
protected void configure(HttpSecurity http) throws Exception {
http
.logout().logoutUrl("/logout").deleteCookies("JSESSIONID").logoutSuccessUrl("/logoutSuccess")
.and()
.authorizeRequests()
.antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll();
// .and().exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
}
Problem using this configuration is, If i request for url say 'http:localhost:8080/showPage' spring security is navigating to 'http:localhost:8080/login' and I am unable to capture anything from original URL. Same problem occurs when I try to use a custom variable targetUrl and using it in the same CustomLoginSuccessHandler.
Please let me know if am taking a wrong approach or something else is missing
Also tried using Custom EntryPoint but unable to redirect using my entrypoint.
#Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint{
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
request.getSession().setAttribute("targetUrl",request.getRequestURL());
redirectStrategy.sendRedirect(request,response,request.getRequestURL().toString());
}
}
Controller :
#RequestMapping(value="/login")
public ModelAndView loginHandler(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
String targetUrl = request.getParameter("targetUrl");
if(targetUrl!=null){ // targetUrl is always null as spring security is navigating to /login asd parameters are lost
request.getSession().setAttribute("url_prior_login",targetUrl);
}
mav.setViewName("login");
return mav;
}
To login, page is navigated to a different domain. and I pass a redirect URL to that domain after successful login it redirects the page back to the redirecturl
<a href="https://domain/sso/identity/login?channel=abc&ru=${externalUrl.applicationUrl}login" >Sign In</a>
Spring Security already stores the request using a RequestCache the default implementation HttpSessionRequestCache stores the last request in the HTTP session. You can access it using the SPRING_SECURITY_SAVED_REQUEST attribute name to get it from the session.
Doing something like this in your controller
public ModelAndView login(HttpServletRequest req, HttpSession session) {
ModelAndView mav = new ModelAndView("login");
if (session != null) {
SavedRequest savedRequest = session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
if (savedRequest != null) {
mav.addObject("redirectUrl", savedRequest.getRedirectUrl());
}
}
return mav;
}
Then in your JSP you can use the redirectUrl to dynamically construct your URL.
http://your.sso/login?url=${redirectUrl}
The final thing you need to do is to make /login accessible for everyone by adding it to the list which is protected by permitAll(). If you don't do this, you will get into a loop or the last request is overwritten and will always point to the login page.
.antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit", "/login").permitAll()
You don't need any other custom classes like EntryPoints or AuthenticationSuccessHandler implementations.
However as you are using SSO it would be probably best to investigate a proper integration with the SSO solution instead of this hack with a login page.
You will at least have one problem : HttpSession session = request.getSession();.
getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
You should use getSession(false) if you want a null return in case there is no session.
In your case you'll never get a null session.
I had the same issue and have solved it by using SavedRequestAwareAuthenticationSuccessHandler as a successHandler to make Spring handle the saved request that was requested before redirecting to login page when user is not logged.
In WebSecurityConfigurerAdapter:
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String LOGIN_PATH = "/login";
#Autowired
MyApplicationAuthenticationSuccessHandler myApplicationAuthenticationSuccessHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
// Set the default URL when user enters a non internal URL (Like https://my-application.com)
myApplicationAuthenticationSuccessHandler.setDefaultTargetUrl("/myapp/home");
http.authorizeRequests().antMatchers("/resources/**").permitAll().antMatchers(LOGIN_PATH).permitAll().antMatchers("/auto/**").authenticated()
.and().formLogin().loginPage(LOGIN_PATH).permitAll()
.successHandler(myApplicationAuthenticationSuccessHandler).and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(LOGIN_PATH)
.invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll().and().sessionManagement().invalidSessionUrl(LOGIN_PATH);
}
}
In custom SavedRequestAwareAuthenticationSuccessHandler:
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
#Component("myApplicationAuthenticationSuccessHandler")
public class MyApplicationAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
try {
super.onAuthenticationSuccess(request, response, authentication);
} catch (ServletException e) {
// redirect to default page (home in my case) in case of any possible problem (best solution in my case)
redirectStrategy.sendRedirect(request, response, "/myapp/home");
}
}
}

Transparent Authentication with Spring Security

I have implemented my server with Spring 4 and Spring Security 3.2.
I am working with two possible scenarios to authentification, it depends from the user client type, web applications, which authentificate throught html form, and mobile client like Android or iOS.
User mobile application can leave to work with the app losing his authentication in the server when the session expire, in this scenario I am trying to authenticate client through Authenticator header param and one custom EntryPoint which can see like this.
public class AuthEntryPoint implements AuthenticationEntryPoint {
#Autowired
private RestProvider restProvider;
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authenticationException)
throws IOException, ServletException {
Device device = (Device) request.getAttribute("device");
if (device.isNormal()) { // WEB
response.sendRedirect(response.encodeRedirectURL(request.getContextPath()));
} else { // MOBILE
DeviceAuth deviceAuth = new DeviceAuth(request.getHeader("Authorization"));
UserAuthToken userAuthToken = (UserAuthToken) this.restProvider.authenticate(
new IncomingToken(
deviceAuth.getEmail(),
null,
"user",
deviceAuth.getNode(),
deviceAuth.getAuthToken())
);
if (userAuthToken != null) {
SecurityContextHolder.getContext().setAuthentication(userAuthToken);
}
if (request.getRequestURI() != null) {
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() +
request.getRequestURI()));
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Not page");
}
}
}
}
Device class is loaded previusly in the request from one custom Filter which analyze the request to determine the device type.
RestProvider is one of the two application Providers which return UserAuthToken, one custom implementation of UsernamePasswordAuthenticationToken.
All this work fine, except redirect question, I want to achieve transparent authentication process, namely, when user leave to work with the application, and return to use it after his server session (and authentication) has been destroyed, server identify bad credentials, get authentication header to authenticate and continue with the request transparently to the app.
How I can do?
Answer my question by myself.
Instead of implement AuthenticationEntryPoint, I had implemented BasicAuthenticationFilter with the same logic that can see in my previous post, removing the normal device control, as normal internet explorers not work with BasicAuthentication.
public class BasicAuthFilter extends BasicAuthenticationFilter {
...
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
...
}
}
HERE you can read more about BasicAuthentication.

Spring 4 API Request Authentication

I am using Spring 4 to create an API and I need to have authentication for the API requests.
Currently, I have created a HandlerInterceptorAdapter to pick out authentication related headers and perform some validation on those values.
If everything is OK, I set the SecurityContext to a custom implementation of Authentication then in the postHandle I set the authentication to null.
Everything works great, except I keep getting warnings in Tomcat7 about ThreadLocal variables not being removed when the application shuts down.
SEVERE: The web application [] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal#6c3e4fdb]) and a value of type [org.springframework.security.core.context.SecurityContextImpl] (value [org.springframework.security.core.context.SecurityContextImpl#ffffffff: Null authentication]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
I get that I may be doing this totally wrong, if so I would love some direction. :D
Here is my interceptor:
/**
* Intercepts Requests to set the Authentication in the SecurityContext.
* Sets the response to 401 - Unauthorized, if the header is missing
*/
#Component
public class AuthenticationHandlerInterceptor extends HandlerInterceptorAdapter {
private HandlerMediator mediator;
Logger log = LoggerFactory.getLogger(AuthenticationHandlerInterceptor.class);
#Autowired
public AuthenticationHandlerInterceptor(HandlerMediator mediator) {
this.mediator = mediator;
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String username = request.getHeader("authentication-username");
String token = request.getHeader("authentication-token");
// if the remote host is local, then override the authentication
if (request.getRemoteHost().equals("0:0:0:0:0:0:0:1") || request.getRemoteHost().equals("127.0.0.1")) {
log.info("On localhost, overriding authentication with localhost");
username = "TEST";
token = "localhost:localhost";
}
if (username == null || username.trim().length() == 0) {
failAuthentication(response, "Missing Authentication Username Header");
return false;
}
if (token == null || token.trim().length() == 0 || !token.contains(":")) {
failAuthentication(response, "Missing Authentication Token Header");
return false;
}
String[] keys = token.split(":");
String appName = keys[0];
String apikey = keys[1];
if (!appName.equals("localhost")) {
// we are not under localhost so we have to authenticate the application calling us
if (mediator.executeCommand(new AuthenticateApplicationCommand(appName, apikey)) == false) {
failAuthentication(response, "Application Token failed authentication");
return false;
}
}
SecurityContextHolder.getContext().setAuthentication(new ApiAuthentication(username, appName));
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
SecurityContextHolder.getContext().setAuthentication(null);
}
private void failAuthentication(HttpServletResponse response, String message) throws Exception {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("text/html;charset=UTF-8");
ServletOutputStream out = response.getOutputStream();
out.println(message);
out.close();
}
}
How do I get rid of these warnings?
Thanks,
Joe
To do authentication based on the content of HTTP headers, the framework foresees a defining custom authentication filter, plugged in the spring security chain via configuration similar to this (see also this answer):
<security:http>
...
<security:custom-filter ref="customAuthenticationFilter" after="SECURITY_CONTEXT_FILTER" />
</security:http>
There in this filter it's possible to add code similar to this (see also BasicAuthenticationFilter):
try {
....
SecurityContextHolder.getContext().setAuthentication(authResult);
} catch (AuthenticationException failed) {
SecurityContextHolder.clearContext();
}
Have a look at class ThreadLocalSecurityContextHolderStrategy,it's there that the SecurityContextImpl instance is getting stored in a ThreadLocal and cleared.
You could try to call clearContext() in AuthenticationHandlerInterceptor, but it's probably better to use the hook the framework foresees as that should lead to less surprises similar to the one you reported.

Primefaces Login Application [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JSF HTTP Session Login
I am using Primefaces to implement my web application. In my implementation the user can log in to the system, then they can load the redirected pages again by copying that URL without login again. How can I prevent this?
Here is my login logic:
public String doLogin() {
if(username != null &&
username.equals("admin") &&
password != null &&
password.equals("admin")) {
msg = "table?faces-redirect=true";
} else
if(user_name.contains(username) &&
pass_word.contains(password) &&
!user_name.contains("admin")) {
msg = "table1?faces-redirect=true";
}
}
return msg;
}
If the user session hasn't expired, then this is normal behavior for web applications. If the session has expired, then you must make sure there is a logged user and that is has the privileges to access to the page he/she's using in the URL. You can achieve this using a Filter.
I'm assuming your web app is on a Java EE 6 container like Tomcat 7 or GlassFish 3.x:
#WebFilter(filterName = "MyFilter", urlPatterns = {"/*.xhtml"})
public class MyFilter implements Filter {
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//get the request page
String requestPath = httpServletRequest.getRequestURI();
if (!requestPath.contains("home.xhtml")) {
boolean validate = false;
//getting the session object
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = (HttpSession)httpServletRequest.getSession();
//check if there is a user logged in your session
//I'm assuming you save the user object in the session (not the managed bean).
User user = (User)session.get("LoggedUser");
if (user != null) {
//check if the user has rights to access the current page
//you can omit this part if you only need to check if there is a valid user logged in
ControlAccess controlAccess = new ControlAccess();
if (controlAccess.checkUserRights(user, requestPath)) {
validate = true;
//you can add more logic here, like log the access or similar
}
}
if (!validate) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.sendRedirect(
httpServletRequest.getContextPath() + "/home.xhtml");
}
}
chain.doFilter(request, response);
}
}
Some implementation for your ControlAccess class:
public class ControlAccess {
public ControlAccess() {
}
public boolean checkUserRights(User user, String path) {
UserService userService = new UserService();
//assuming there is a method to get the right access for the logged users.
List<String> urlAccess = userService.getURLAccess(user);
for(String url : urlAccess) {
if (path.contains(url)) {
return true;
}
}
return false;
}
}
While looking for a nice way to explain this, I found a better answer from BalusC (JSF expert). This is JSF 2 based:
JSF HTTP Session Login
You can do form based authentication to protect your inner pages from being accessed by unauthenticated users.
You can also let the container handle the authentication for you using JDBC realm authentication as in this example

Categories

Resources