How to catch user and password from angularJS client into spring security - spring

I have implemented a demo client in angular that sends the username and password as POST to a REST Api that reads that and do some auth logic. the thing is that in the controller always catch as null (no user no pass). I have tried send the same data in Advanced Rest Client in Chrome, and everything works OK.
here's my snippet code:
Angular client:
function LoginCtrl($scope, $rootScope, $location, $http, LoginService) {
$scope.submit = function() {
LoginService.authenticate($.param({username: $scope.inputUsername, password: $scope.inputPassword}), function(user) {
$rootScope.user = user;
$http.defaults.headers.common['Authentication'] = user.token;
$location.path("/");
});
};
};
Controller java (First Try):
public #ResponseBody UserTransfer authenticate(HttpServletRequest request) throws IOException {
//tried this one first but NULL this two params.
String username = request.getParam("username");
String password = request.getParam("password");
//somer logic
return new UserTransfer(userDetails.getUsername(), roles, TokenUtils.createToken(userDetails));
Controller java (Second Try):
public #ResponseBody UserTransfer authenticate(#RequestParam("username") String username, #RequestParam("password") String password) throws IOException {
//tried secondly this one but in this case the server responded with ERROR 400 - Bad Request
//somer logic
return new UserTransfer(userDetails.getUsername(), roles, TokenUtils.createToken(userDetails));
What would be the correct way to pass this data from Angular to my controller?, I cannot see the error...
thanks for your help!!!

had the same problem
use Jersey to deal with that
web.xml
<servlet>
<servlet-name>RestService</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.pearson.taxonomy.cm.web.controller</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>RestService</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
UserResource.java
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.HashMap;
import java.util.Map;
#Component
#Path("/user")
public class UserResource {
#Autowired
private UserDetailsService userService;
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authManager;
#Path("authenticate")
#POST
#Produces(MediaType.APPLICATION_JSON)
public UserView authenticate(#FormParam("username") String username, #FormParam("password") String password) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
Authentication authentication = this.authManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
Map<String, Boolean> roles = new HashMap<String, Boolean>();
UserDetails userDetails = this.userService.loadUserByUsername(username);
for (GrantedAuthority authority : userDetails.getAuthorities()) {
roles.put(authority.toString(), Boolean.TRUE);
}
return new UserView(userDetails.getUsername(), roles, TokenUtils.createToken(userDetails));
}
}

Related

#ExceptionHandler not being triggered?

I have seen other duplicate stack overflow issues on this topic but none seem to replicate my situation.
When throwing an exception, my ExceptionHandler class is not picking it up and returning json, instead the default 500 code with the exception details is returned as HTML to the client. I have checked and Spring does initialise my ExceptionHandler class but for whatever reason the methods aren't called.
GlobalExceptionHandler.class:
#ControllerAdvice
#RequestMapping(produces = "application/json")
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
public GlobalExceptionHandler(){
LOG.debug("This gets called in logs...");
}
#ExceptionHandler({CustomException.class})
public #ResponseBody ResponseEntity<Object> handleCustomException(HttpServletRequest request,
CustomException ex) {
LOG.debug("This does not get called...");
Map<String, Object> response = new HashMap<>();
response.put("message", ex.getMessage());
return new ResponseEntity<>(response, ex.getCode());
}
}
CustomException.class:
public class CustomException extends RuntimeException{
private HttpStatus code;
private String message;
public CustomException(final HttpStatus code, final String message){
this.code = code;
this.message = message;
}
/**
* Gets message.
*
* #return Value of message.
*/
public String getMessage() {
return message;
}
/**
* Sets new code.
*
* #param code
* New value of code.
*/
public void setCode(HttpStatus code) {
this.code = code;
}
/**
* Sets new message.
*
* #param message
* New value of message.
*/
public void setMessage(String message) {
this.message = message;
}
/**
* Gets code.
*
* #return Value of code.
*/
public HttpStatus getCode() {
return code;
}
}
The exception handler is triggered here:
#Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private JwtTokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain
filterChain) throws ServletException, IOException {
logger.debug("Filtering request for JWT header verification");
String jwt = getJwtFromRequest(request);
logger.debug("JWT Value: {}", jwt);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken
(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
logger.error("{}", new CustomException(HttpStatus.UNAUTHORIZED, "No Valid JWT Token Provided"));
throw new CustomException(HttpStatus.UNAUTHORIZED, "No Valid JWT Token Provided");
}
filterChain.doFilter(request, response);
}
}
I have all necessary properties in web config:
<!--<context:annotation-config />-->
<tx:annotation-driven/>
<context:component-scan base-package="com.app.controller"/>
My Web.xml:
<web-app>
<!-- For web context -->
<servlet>
<servlet-name>appDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Logging -->
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>/WEB-INF/classes/logback.xml</param-value>
</context-param>
<filter>
<filter-name>jwtFilter</filter-name>
<filter-class>com.app.controller.security.filters.JwtAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jwtFilter</filter-name>
<servlet-name>appDispatcher</servlet-name>
</filter-mapping>
</web-app>
Been going over this issue for a while..
This is all I get:
Your exception is not getting catched by the #ControllerAdvice because you are throwing it from a class annotated with #Component and not #Controller.
As per the documentation:
Specialization of #Component for classes that declare
#ExceptionHandler, #InitBinder, or #ModelAttribute methods to be
shared across multiple #Controller classes.
You can find a more complete reference here.

How to have jersey inject a param based on the http header?

I have an interface and would like to open it as a REST API.
Interface:
string createToken(String username, String scopes);
REST web API:
#GET
#Path("/createToken")
#Override
public string createToken(#InjectParam String username, String scopes) {
...
}
As a simple Java API,, the interface itself makes sense - creating an access token by a specific (unique) user.
But, as an REST web API, I need a previous step to retrieve the username, based on some user data that is passed in the http header, like an SSO key.
How do I inject a value into the username - extracted from the HTTP header? Thanks.
Created a Provider to inject the value into a custom annotation. See small working example here. See source inline below as well.
The example extracts the username from an sso token. It's a dummy extraction.
* I didn't use #InjectParam.
Invocation example:
curl -X POST -H "ssoToken: 1234" http://localhost:8080/JerseyCustomParamInjection-1.0-SNAPSHOT/oauth2/createAccessToken
Custom annotation:
#Target({ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
public #interface LoggedUser {
}
Provider to do the injection:
#Provider
public class LoggedUserProvider implements
Injectable<String>,
InjectableProvider<LoggedUser, Parameter> {
#Context
private HttpServletRequest request;
public LoggedUserProvider() {
}
#Override
public Injectable<String> getInjectable(ComponentContext cc, LoggedUser a, com.sun.jersey.api.model.Parameter c) {
return this;
}
#Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
#Override
public String getValue() {
String sso = request.getHeader("ssoToken");
if (sso == null) {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
// Retreive username from soo
String username = " <extracted username from sso="+sso+">";
return username;
}
}
Resource that defines the wants to inject the value:
#Path("/oauth2")
public class Resource {
#POST
#Path("/createAccessToken")
public String createAccessToken(
#LoggedUser String username
) {
return username + " <created access token using the logged in injected username>";
}
}
Servlet configuration (web.xml):
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Restful Web Application</display-name>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>info.fastpace.jerseycustomparaminjection</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
You should use HeaderParam. See this
#GET
#Path("/createToken")
#Override
public string createToken(#HeaderParam("username") String username, String scopes) {
...
}
If you have to extract username and have to inject it, you will have to implement a provider:
#Provider
public class UsernameProvider
extends AbstractHttpContextInjectable<Locale>
implements InjectableProvider<Context, Type> {
#Override
public Injectable<E> getInjectable(ComponentContext compCntxt, Context cntxt, Type typ) {
if (typ.equals(String.class)) {
return this;
}
return null;
}
#Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
#Override
public String getValue(HttpContext httpCntxt) {
final Request rqst = httpCntxt.getRequest();
String username = null;
//Extract 'username' from Headers
return username;
}
}
Detailed explanation here

Jersey custom ExceptionMapper not called on 400 Bad Request (when validation fails)

I'm using Jersey with Spring for web services. For catching exceptions and formatting the response sent to the caller I have added an implementation of ExceptionMapper.
Though it is being called when I explicitly throw an exception from within the controller, but when the json field validation fails the exception mapper is not called and the response sent is **may not be null (path = checkNotification.arg0.tyres, invalidValue = null)
**
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable ex) {
System.out.println("Exception Mapper !!!");
return Response.status(404).entity(ex.getMessage()).type("application/json").build();
}
}
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
com.help.rest.controller,
com.fasterxml.jackson.jaxrs.json
</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.help.filter.FeatureRegistration</param-value>
</init-param>
<init-param>
<param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Jersey Version is 2.22.1
Spring Version is 4.2.4
I made it work by changing
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable ex) {
System.out.println("Exception Mapper !!!");
return Response.status(404).entity(ex.getMessage()).type("application/json").build();
}
}
to
#Provider
public class GenericExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException ex) {
System.out.println("Exception Mapper !!!");
return Response.status(404).entity(ex.getMessage()).type("application/json").build();
}
}
Though I'm able to catch the exception I am not getting the exact class and field which failed the constraint.
Resolved
Found a Set containing all the required fields in ContraintViolationException, could be accessed using ex.getConstraintViolations()
made it work by changing
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable ex) {
System.out.println("Exception Mapper !!!");
return Response.status(404).entity(ex.getMessage()).type("application/json").build();
}
}
to
#Provider
public class GenericExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
#Override
public Response toResponse(ConstraintViolationException ex) {
System.out.println("Exception Mapper !!!");
return Response.status(404).entity(ex.getMessage()).type("application/json").build();
}
}
To get the exact exception details, like which field failed the constraint use ConstraintViolationException's getConstraintViolations(). This method provides a set for all the constraint violations.
You need to register it:
public class MyApplication extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorldResource.class);
/** you need to add ExceptionMapper class as well **/
s.add(GenericExceptionMapper.class)
return s;
}
}

How to redirect any url that do not match any #RequestMapping parameter in the application

I use Spring MVC in my web application. I am trying to redirect any url that match the pattern http://localhost:8080/my-app/* to a specific controller. But if the url is something like the following, http://localhost:8080/my-app/test and if there is a controller as follows:
#Controller
#RequestMapping("test")
public class TestClass
{
#RequestMapping(value = "/landing", method = RequestMethod.GET)
public String selectHomePage(ModelMap model)
{
//do something
}
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String listFaqCollections(#ModelAttribute("ownedby") String ownedBy, ModelMap model)
{
//do something
}
}
And I have another class as follows:
#Controller
public class InvalidUrslRedirect
{
#RequestMapping(method = RequestMethod.GET)
public String redirectInvalidUrls(Model model)
{
//do something
}
All the urls that are invalid will be redirected to the above controller class.
The valid urls would be as follows:
http://localhost:8080/my-app/test/landing
http://localhost:8080/my-app/test/list?ownedby=me
But if the url is something like:
http://localhost:8080/my-app/test/list?ownedbys=me
the normal tomcat 404 error page is displayed and the it is not getting redirected to the InvalidUrslRedirect class
In my web.xml file, I have the following:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/core/root-context.xml, classpath:spring/core/spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
In the spring-security.xml, I have:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/**" access="isFullyAuthenticated()"/>
I have been searching the net for some time now, but could not find much help. is there any way i can achieve such a functionality. Thanks in advance
If i understood you correctly, you want to redirect every request other than e.g. "/test". In this case you'll need two methods:
#RequestMapping(method = RequestMethod.GET)
public String redirectEverythingOtherThanTest(){
return "redirect:/pageToRedirectTo.html"
}
#RequestMapping(value="/test", method = RequestMethod.GET)
public String testRequest(){
//some stuff
return "somepage.html";
}
Also remember about #Controller annotation on your class.
How is your web application setup? Which URLs is Spring looking for? Do you have an AbstractAnnotationConfigDispatcherServletInitializer?
public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* Configure Spring MVC to handle ALL requests
*/
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Class<?>[] getRootConfigClasses() {
....
}
#Override
protected Class<?>[] getServletConfigClasses() {
....
}
#Override
public void onStartup(ServletContext container) throws ServletException {
...
}
}

Liferay 6.2 + Spring #Autowired not working in a hook

I am using Spring 4.0.6 with Liferay 6.2. Spring isn't able to inject autowired components in to the hook, object comes as null. I have also tried with spring version 3.1 that comes with liferay. Same code works in portlets but not in hooks.
private ApplicationEventPublisher publisher in ActivityEventPublisher.java is null.
web.xml
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web- app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>com.liferay.portal.kernel.servlet.SecurePluginContextListener</listener- class>
</listener>
<listener>
<listener-class>com.liferay.portal.kernel.servlet.PortletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
</web-app>
ActivityEventPublisher.java
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import connect.activity.solr.document.ActivityData;
#Component
public class ActivityEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
#Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public ApplicationEventPublisher getPublisher() {
return publisher;
}
public void setPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void publish(ActivityData data) {
ActivityEvent event = new ActivityEvent(this);
event.setActivityData(data);
this.publisher.publishEvent(event);
}
}
Any help will be much appreciated.
Thanks
Unfortunately, autowired mechanisms are not allowed in hooks, wrappers or startup actions at Liferay.
You can implement an ApplicationContextProvider, it's so easy and useful:
#Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx = null;
public static ApplicationContext getApplicationContext() {
return ctx;
}
#Override
public void setApplicationContext(ApplicationContext ac) throws BeansException {
ctx = ac;
}
}
An example of use in a Hook will be the following:
public class PostLoginActionHook extends Action {
// That code "replaces" #Autowired annotation
private final UserProxyService userProxyService = (UserProxyService) ApplicationContextProvider.
getApplicationContext().getBean(UserProxyService.class);
#Override
public void run(HttpServletRequest request, HttpServletResponse response) throws ActionException {
UserVO myCustomUser = userProxyService.getCustomUserByLiferayUser(user.getUserId());
{...}
}
Hope it helps!

Resources