Showing posts with label spring-mvc. Show all posts
Showing posts with label spring-mvc. Show all posts

Thursday, October 4, 2018

Java/Spring MVC: provide request context to child threads

Leave a Comment

I have the Problem, that I want to outsource some processes of my Spring WebMVC application into separate Threads. That was easy enough and works, until I want to use a class, userRightService, which uses the global request. That's not available in the threads, and we get a problem, that's pretty much understandable.

This is my Error:

java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.userRightsService': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is  java.lang.IllegalStateException: Cannot ask for request attribute -  request is not active anymore! 

Okay, clear enough. I am trying to keep the request context by implementing this solution:

How to enable request scope in async task executor

This is my runnable class:

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) public class myThread implements Runnable {    private RequestAttributes context;    public DataExportThread(RequestAttributes context) {     this.context = context;   }    public void run() {     RequestContextHolder.setRequestAttributes(context); 

And this where it gets spawned:

final DataExportThread dataExportThread =     new myThread(RequestContextHolder.currentRequestAttributes());  final Thread thread = new Thread(myThread); thread.setUncaughtExceptionHandler((t, e) -> {...}); thread.start(); 

As far as I understood, we store the currentRequestAttributes in the thread and then, when running, we restore them currentRequestAttributes... sounded solid to me, but the error is still there. I think I made some mistake adapting the solution for my case. maybe someone can help me finding the error.

Before I went through a lot of stackoverflow-threads with different solutions (see below), so I could try something else next, but this one seemed the clearest and simplest to me, so I hope someone could help me finding the mistake in the implementation or explain why it's the wrong approach.

I already tried this one without success:

If it's matters:

<org.springframework-version>4.3.4.RELEASE</org.springframework-version> 

BTW: I know that it would be better to restructure the application in a way, that the request is not needed in the thread but that's very complicated in that case and I really hope I could avoid this.

--

Edit1:

The Bean which can not be created in the thread starts like this:

@Service("userRightsService") @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) public class UserRightsService { 

--

Edit2:

I also tried this one:

But context is always empty...

1 Answers

Answers 1

I couldn't reproduce the problem as I am not sure how are you creating/injecting the UserRightsService but I have a couple of suggestions that you may try.

I guess that the problem is that the RequestAttributes is invalidated as the request is over (that's why the exception says Cannot ask for request attribute - request is not active anymore), which happens as your task is running.

Instead, you could try injecting the UserRightsService where your thread is spawned and pass this instance as an argument to the thread. That way the UserRightsService should be created without problem as the request should be still available.

Even so, trying to access the RequestAttributes after the request is over will probably fail. In that case I propose to make a copy of all the values that you need before the request is over, i.e. before your run the thread.

If that doesn't work for you please provide some more info regarding how you initialize the UserRightsService inside the task.

Good luck!

P.S.: I think that the scope annotation in your thread class is useless as the task object is created manually and not managed by spring.

Read More

Wednesday, September 12, 2018

Spring MVC - should my domain classes implement Serializable for over-the-wire transfer?

Leave a Comment

I'm trying to learn Spring Boot by implementing a simple REST API.

My understanding was that if I need to transfer an object over the wire, that object should implement Serializable.

In many examples on the net though, including official ones, domain classes that need to be transferred from server to client (or vice-versa) do not to implement Serializable.

For instance: https://spring.io/guides/gs/rest-service/

But in some cases, they do:

For instance: https://github.com/szerhusenBC/jwt-spring-security-demo/blob/master/src/main/java/org/zerhusen/security/JwtAuthenticationRequest.java

Is there a general rule of thumb on when to implement Serializable?

4 Answers

Answers 1

Using the Java serialization API means you need something in Java on the other side of the wire to deserialize the objects, so you have to control the code that deserializes as well as the code that serializes.

This typically isn't relevant for REST applications, consuming the application response is the business of someone else's code, usually outside your organization. When building a REST application it's normal to try to avoid imposing limitations on what is consuming it, picking a format that is more technology-agnostic and broadly available.

Some reasons for making an object serializable would be:

  • so you can put it in an HttpSession

  • so you can pass it between tiers in a distributed application

  • so you can save it to the file system and restore it later (for instance, you could make the contents of a queue serializable and have the queue contents saved when the application shuts down, reading from the save location when the application starts to restore the queue to its state on shutdown).

In all these cases, you serialize so you can save something to a filesystem or send it across a network.

Answers 2

There are many ways to serialize an object. Java's object serialization is just one of them. From the official documentation:

To serialize an object means to convert its state to a byte stream

REST APIs usually send and receive JSON or XML. In that case serializing an object means converting its state to a String.

There is no direct connection between "sending an object over the wire" and implementing Serializable. The technologies you use dictate whether or not Serializable has to be implemented.

Answers 3

that's a good question when to implement Serializable interface.

these links can provides some useful contents:

Serializing java.io.Serializable instance into JSON with Spring and Jackson JSON

When and why JPA entities should implement Serializable interface?

I sometimes wonder about this,and I think

Because Java is a open source language,and more libraries providered by third party.for tells who will serialize and deserialize the object,the java offical declare a constract interface,makes transfer easy and safety throught different library.

It's just a constract,most third-party libraries can serialize/deserialize when checking implement this constract.and jackson's jar library is not use it.

So you can deem if you use serialize/deserialize object data in your own system,and simple process,likes just serialize and response it(jackson in spring MVC),you needn't to implements it. but if you used in other jar library,likes saving in HttpSession,or other third-party componens/library,you should(or have to) implement Serializable,otherwise the libraries will throw a exception to tell you the constract interfaced which it knows is not provide.

But they said it's a good habit and best properties that to implement the Serializable when serialize a custom class. :)

Answers 4

The specific examples you have mentioned do not transfer objects over the wire. From the example links I see that the controller methods return a domain object with ResponseBody annotation. Just because the return type of the method is the domain object it is not necessary that the whole object is being sent to the client. One of the handler method in Spring mvc framework internally intercepts the invocation and determines that the method return type does not translate to direct ModelAndView object. RequestResponseBoodyMethodProcessor which handles the return value of such annotated methods and uses one of the message converters to write the return object to the http response body. In the case the message converter used would be MappingJackson2HttpMessageConverter. So if are to follow the same coding style you are not required to implement Serializable for your domain objects.

Have a look at this link for the Http message converters provided by default from spring. The list is quiet extensive however not exhaustive and if requirements arise you can implement your own custom message converter to user as-well.

Read More

Monday, August 13, 2018

Spring MVC @RequestParam - empty List vs null

Leave a Comment

By default Spring MVC assumes @RequestParam to be required. Consider this method (in Kotlin):

fun myMethod(@RequestParam list: List<String>) { ... } 

When passing empty list from javaScript, we would call something like:

$.post("myMethod", {list: []}, ...) 

In this case however, as the list is empty, there is no way to serialize empty list, so the parameter essentially disappears and so the condition on required parameter is not satisfied. One is forced to use the required: false on the @RequestParam annotation. That is not nice, because we will never receive the empty list, but null.

Is there a way to force Spring MVC always assume empty lists in such case instead of being null?

4 Answers

Answers 1

This can be managed in the serialization with ObjectMapper. If you are using jackson in your spring MVC, you can do either the following.

  • Configure your object mapper.
    objectMapper.configure(SerializationConfig.Feature.WRITE_EMPTY_JSON_ARRAYS, false);  
  • Or if you are using beans via xml config. <bean name="objectMapper" class="org.springframework.http.converter.json.JacksonObjectMapperFactoryBean" autowire="no"> <property name="featuresToDisable"> <list> <value type="org.codehaus.jackson.map.SerializationConfig.Feature">WRITE_EMPTY_JSON_ARRAYS</value> </list> </property>

Answers 2

Tried this?

fun myMethod(@RequestParam list: List<String> = listOf()) { ... } 

Answers 3

You can try a WebDataBinder in your controller.

@InitBinder public void initBinder(WebDataBinder binder) {     binder.registerCustomEditor(List.class, "list", new CustomCollectionEditor( List.class, true)); } 

Answers 4

To get Spring to give you an empty list instead of null, you set the default value to be an empty string:

@RequestParam(required = false, defaultValue = "") 
Read More

Monday, June 11, 2018

Should I put the ID of my entity in the URL or into the form as a hidden field?

Leave a Comment

I think in terms of REST, the ID should be placed into the URL, something like:

https://example.com/module/[ID]

and then I call GET, PUT, DELETE on that URL. That's kind of clear I think. In Spring MVC controllers, I'd get the ID with @PathVariable. Works.

Now, my practical problem with Spring MVC is, that if I do this, I have to NOT include the ID as part of the form (as well), Spring emits warnings of type

Skipping URI variable 'id' since the request contains a bind value with the same name. 

otherwise. And it also makes kind of sense to only send it once, right? What would you do if they don't match??

That would be fine, but I do have a custom validator for my form backing bean, that needs to know the ID! (It needs to check if a certain unique name is already being used for a different entity instance, but cannot without knowing the ID of the submitted form).

I haven't found a good way to tell the validator that ID from @PathVariable, since the validation happens even before code in my controller method is executed.

How would you solve this dilemma?

This is my Controller (modified):

@Controller @RequestMapping("/channels") @RoleRestricted(resource = RoleResource.CHANNEL_ADMIN) public class ChannelAdminController {     protected ChannelService channelService;     protected ChannelEditFormValidator formValidator;      @Autowired     public ChannelAdminController(ChannelService channelService, ChannelEditFormValidator formValidator)     {         this.channelService = channelService;         this.formValidator = formValidator;     }      @RequestMapping(value = "/{channelId}/admin", method = RequestMethod.GET)     public String editChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") ChannelEditForm channelEditForm, Model model)     {         if (channelId > 0)         {             // Populate from persistent entity         }         else         {             // Prepare form with default values         }         return "channel/admin/channel-edit";     }      @RequestMapping(value = "/{channelId}/admin", method = RequestMethod.PUT)     public String saveChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") @Valid ChannelEditForm channelEditForm, BindingResult result, Model model, RedirectAttributes redirectAttributes)     {         try         {             // Has to validate in controller if the name is already used by another channel, since in the validator, we don't know the channelId             Long nameChannelId = channelService.getChannelIdByName(channelEditForm.getName());             if (nameChannelId != null && !nameChannelId.equals(channelId))                 result.rejectValue("name", "channel:admin.f1.error.name");         }         catch (EmptyResultDataAccessException e)         {             // That's fine, new valid unique name (not so fine using an exception for this, but you know...)         }          if (result.hasErrors())         {             return "channel/admin/channel-edit";         }          // Copy properties from form to ChannelEditRequest DTO         // ...          // Save         // ...          redirectAttributes.addFlashAttribute("successMessage", new SuccessMessage.Builder("channel:admin.f1.success", "Success!").build());         // POST-REDIRECT-GET         return "redirect:/channels/" + channelId + "/admin";     }       @InitBinder("channelForm")     protected void initBinder(WebDataBinder binder)     {         binder.setValidator(formValidator);     } } 

4 Answers

Answers 1

The cleanest way to solve this, I think, is to let the database handle the duplicates: Add a unique constraint to the database column. (or JPA by adding a @UniqueConstraint) But you still have to catch the database exception and transform it to a user friendly message.

This way you can keep the spring MVC validator simple: only validate fields, without needing to query the database.

Answers 2

I think I finally found the solution.

As it turns out Spring binds path variables to form beans, too! I haven't found this documented anywhere, and wouldn't have expected it, but when trying to rename the path variable, like @DavidW suggested (which I would have expected to only have a local effect in my controller method), I realized that some things got broken, because of the before-mentioned.

So, basically, the solution is to have the ID property on the form-backing object, too, BUT not including a hidden input field in the HTML form. This way Spring will use the path variable and populate it on the form. The local @PathVariable parameter in the controller method can even be skipped.

Answers 3

What ever you said is correct the correct way to design rest api is to mention the resource id in path variable if you look at some examples from the swagger now as open api you could find similar examples there

for you the correct solution would be to use a custom for validator like this

import javax.validation.Validator;` import org.apache.commons.lang3.StringUtils;` import org.springframework.validation.Errors;` importorg.springframework.validation.beanvalidation.CustomValidatorBean;`  public class MyValidator extends CustomValidatorBean {`     public void myvalidate(Object target,Errors errors,String flag,Profile profile){         super.validate(target,errors);         if(StringUtils.isEmpty(profile.name())){             errors.rejectValue("name", "NotBlank.profilereg.name", new Object[] { "name" }, "Missing Required Fields");         }             }             } 

This would make sure all the fields are validated and you dont need to pass the id in the form.

Answers 4

Could you not simply disambiguate the 2 (URI template variables vs. parameters) by using a different name for your URI template variable?

@RequestMapping(value = "/{chanId}/admin", method = RequestMethod.PUT) public String saveChannel(@PathVariable Long chanId, @ModelAttribute("channelForm") @Valid ChannelEditForm channelEditForm, BindingResult result, Model model, RedirectAttributes redirectAttributes) { [...] 
Read More

Friday, June 8, 2018

How to secure a MVC application with OAuth2 using Spring?

Leave a Comment

Sorry my english.

I have an application I can login in usual way.

@Configuration @EnableWebSecurity public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {      @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         System.out.println("LoginSecurityConfig :: configure");          auth.jdbcAuthentication().dataSource( getDataSource() )             .passwordEncoder( new BCryptPasswordEncoder(16) )             .usersByUsernameQuery(                 "select user_name as username,password,enabled from users where user_name=?")             .authoritiesByUsernameQuery(                 "select user_name as username, role_name from users_roles ur join users u on ur.user_id = u.user_id and u.user_name = ?");      }      @Override     protected void configure(HttpSecurity http) throws Exception {           http         .csrf().disable()         .authorizeRequests()         .antMatchers("/login*").anonymous()         .antMatchers("/resources/**").permitAll()         .antMatchers("/fotos/**").permitAll()         .antMatchers("/users").access("hasRole('ROLE_ADMIN')")         .antMatchers("/user").access("hasRole('ROLE_ADMIN')")         .anyRequest().authenticated()         .and()          .formLogin()         .loginPage("/loginPage")         .defaultSuccessUrl("/home", true)         .failureUrl("/loginPage?error=true")         .loginProcessingUrl("/login")         .usernameParameter("username")         .passwordParameter("password")         .and()          .logout()         .logoutSuccessUrl("/loginPage")         .invalidateHttpSession(true);         }      } 

Using this I can try to access any secured resource and the system sends me to the loginPage where I can post username and password to the internal login controller then I have the Principal and can access the secured resources ( home, users, user ). Working fine.

But... I need to remove the user control database stuff and use OAuth2 to allow same kind of access. I don't want to have any users in my database anymore. I need a login screen and then a token request like http://myserver/oauth/token?grant_type=password&username=admin&password=admin passing client_id and client_secret in Basic. I know how to do the "get token" part and my server is working fine and give me the token and refresh token but only using Postman because I have no idea how to use it in my web application code. All tutorials I've found are using both Server and Client in same application and actually don't show how to consume an OAuth2 remote server.

Already try to use this. It is an excelent tutorial and very near to what I need but too complex to me.

I have this code and understand it can use the server and issue a token using the client credentials, but don't know how to give to the user a login screen and take his credentials to complete the request (the GET part).

@Configuration @EnableResourceServer public class OAuth2ResourceServerConfigRemoteTokenService extends ResourceServerConfigurerAdapter {      @Override     public void configure(final HttpSecurity http) throws Exception {                 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)                     .and()                     .authorizeRequests().anyRequest().permitAll();                   }      @Primary     @Bean     public RemoteTokenServices tokenServices() {         final RemoteTokenServices tokenService = new RemoteTokenServices();         tokenService.setCheckTokenEndpointUrl("http://myoauthserver/oauth/check_token");         tokenService.setClientId("clientid");         tokenService.setClientSecret("password");         return tokenService;     }  } 

so... how can I secure my system, take login and password from the user and use this code to controll credentials like I were using usual database method?

Or OAuth2 is only for secure REST API?

enter image description here

Please be newbie friendly because I'm not very confortable using Spring.

2 Answers

Answers 1

Simple as 1,2,3 ...

Just change a little my OAuth2 server to accept oauth/authorize method.

@Override protected void configure(HttpSecurity http) throws Exception {      http         .requestMatchers()         .antMatchers("/login", "/oauth/authorize")     .and()         .authorizeRequests()         .anyRequest()         .authenticated()     .and()         .formLogin()         .permitAll();        } 

and create a custom login form. Now all clients (web applications) can login into it.

Here you can find a sample client and a more details: http://www.baeldung.com/sso-spring-security-oauth2

Answers 2

I’ve been working on this myself recently, and I wish I could say I have a simple answer, but I don’t. I would have to start by asking questions like, is this a web application (JSP etc) or a REST API used by a web application, or a REST API used by a mobile app, etc etc. The reason this is important is that you first have to select one of the OAuth2 profiles and grant types, and they all have different requirements and configuration in Spring. Also, are you trying to integrate with a third party OAuth2 authentication provider (e.g. Facebook) or is your application acting as both the authentication provider (where login and password validation occurs) and the protected resource (where the web page requests or API calls go to)? So I guess the best I can do is assign you some homework: (1) Read about the various OAuth2 profiles and determine which one best fits your application, and learn all the terminology (like, what is a client secret?). This is definitely NOT one of those cases where you can just cut and paste example code without understanding it. If you don’t have a reasonable understanding of how OAuth2 works you are going to have a lot of difficulty. Also: we’re talking about SECURITY here so doing stuff without understand it is a very bad idea. If you aren’t careful, you may think it’s working but in fact you’re leaving yourself wide open to attacks. (2) if you are not familiar with Spring Framework Security you’ll need a basic grounding in that to understand what you’re doing, (3) Once you have an idea which profile you’ll use, use that in a google search, e.g. “Spring oauth2 implicit grant” to find an example tailored for that profile. There are a few out there and that’s a good place to start though I found I was not able to take any of the examples directly over to my application because of subtle differences in their assumptions and my application. The Spring reference guide is helpful also but doesn’t necessarily give all the details for all the issues you may encounter. Finally, try to implement with your application. You’ll want some good tools to send requests to your app (I like PostMan for that purpose) so you can inspect the data going back and forth. OAuth2 involves a complex series of HTTP redirects so testing can be a bit difficult. Also, be patient. I consider myself a Spring expert and it still took me a few days to get things fully working the way I wanted. Note that there is actually VERY LITTLE code you end up writing, but getting the small amount of code exactly right is what’s difficult.

Read More

How to fill a map inside a map inside a Spring form?

Leave a Comment

I have the following form

public class myForm { private String code; (getter and setter) private Map<String, Map<String, Object>> map(getter and setter) } 

I can fill the code attribute easily but i don't know how to proceed to fill the map, i don't even know if it's possible ...

This is my Spring form

<form:form commandName="myForm" action="${PostUrl}" method="POST" >   <input type="hidden" path="code" value="78967" />   <input type="submit" value="Submit"/> </form:form> 

I will know the key of the first map and i will know the key of the second map, only the value of the second map will be enter by the user.

To try to be as clear as possible here is in java what i wish to do with my form

Map<String, Map<String, Object>> map1 = new HashMap<String, map<String,  Object>>(); Map<String, Object> map2 = new HashMap<String, Object>(); map2.put("DatePickerLabel", DatePickedByTheUser) map1.put("DATEPICKER", map2) 

1 Answers

Answers 1

As there is best option you can do it by the help of inner bean .

public class myForm { private String code; (getter and setter) private Map<String,InnerBeanObject> map(getter and setter) } 

And if you are using inner bean you can do a setter injection to fill your

Map<String, Object> 

If you are using xml bean configuration

    <beans xmlns="http://www.springframework.org/schema/beans"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://www.springframework.org/schema/beans         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">          <bean id="MyFormBean" class="Myform">          <property name="code" >          <property name="map">             <map>             <entry key="Key " value-ref="innerBean"></entry>             </map>         </property>         </bean>         <bean id="innerBean" class="InnerBean">                     <property name="InnerBeanMap">                     <map>                       //get ur bean map key and value                    </map>         </bean>       </beans> 

There is similar way by java code also as you know if you are using earlier version of spring.by annotation @bean

Read More

Sunday, May 13, 2018

Field error in object 'user' on field 'userProfiles': rejected value [3];

Leave a Comment

I have downloaded a working demo which working perfectly fine while I ran it. But when I have just made my way and I am using same page and functionality with registration page and then I submitting the form I am getting error:

[Field error in object 'user' on field 'userProfiles': rejected value [3]; codes [typeMismatch.user.userProfiles,typeMismatch.userProfiles,typeMismatch.java.util.Set,typeMismatch]; arguments      [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.userProfiles,userProfiles]; arguments []; default message [userProfiles]]; default message  [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Set' for property 'userProfiles'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type  [com.idev.tpt.model.UserProfile] for property 'userProfiles[0]': no matching editors or conversion strategy found]] 

JSP File:

<form:form id="userForm" action="newuser" modelAttribute="user">     <form:input type="hidden" path="id" id="id" />     <div class="form-group">         <form:input type="text" path="firstName" id="firstName" placeholder="First Name" class="form-control input-sm" />     </div>     <div class="form-group">         <form:input type="text" path="lastName" id="lastName" placeholder="Last Name" class="form-control input-sm" />     </div>     <div class="form-group">         <c:choose>             <c:when test="${edit}">                 <form:input type="text" path="ssoId" id="ssoId" placeholder="SSO ID" class="form-control input-sm" disabled="true" />             </c:when>             <c:otherwise>                 <form:input type="text" path="ssoId" id="ssoId" placeholder="SSO ID" class="form-control input-sm" />                 <div class="has-error">                     <form:errors path="ssoId" class="help-inline" />                 </div>             </c:otherwise>         </c:choose>     </div>     <div class="form-group">         <form:input type="password" path="password" id="password" placeholder="password" class="form-control input-sm" />         <div class="has-error">             <form:errors path="password" class="help-inline" />         </div>     </div>     <div class="form-group">         <form:input type="text" path="email" id="email" placeholder="email" class="form-control input-sm" />         <div class="has-error">             <form:errors path="email" class="help-inline" />         </div>     </div>      <div class="form-group">         <form:select path="userProfiles" items="${roles}" multiple="true" itemValue="id" itemLabel="type" class="form-control input-sm" />     </div>     <!-- <div class="form-group">                                             <textarea class="form-control" id="prop_note" name="note" placeholder="Note" ></textarea>                                         </div> -->     <p class="demo-button btn-toolbar">         <span id="warningLbl" class="label label-warning" style="display: none;"></span>         <button id="propAddBtn" type="submit" class="btn btn-primary pull-right">Save</button>         <button id="propUpdateBtn" type="submit" class="btn btn-primary pull-right" style="display: none;">Update</button>&nbsp;         <button id="propClearBtn" type="button" class="btn btn-primary pull-right" style="display: none;">Clear</button>     </p>     <br> </form:form> 

controller:

@RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)     public String newUser(ModelMap model) {         User user = new User();         model.addAttribute("user", user);         model.addAttribute("edit", false);         model.addAttribute("roles", userProfileService.findAll());         model.addAttribute("loggedinuser", getPrincipal());         return "registration";     }      /**      * This method will be called on form submission, handling POST request for      * saving user in database. It also validates the user input      */     @RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)     public String saveUser(@Valid User user, BindingResult result,             ModelMap model) {         if (result.hasErrors()) {             return "registration";         }          if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){             FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));             result.addError(ssoError);             return "registration";         }          userService.saveUser(user);          model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");         model.addAttribute("loggedinuser", getPrincipal());         //return "success";         return "registrationsuccess";     } 

Model :

package com.websystique.springmvc.model;  import java.io.Serializable; import java.util.HashSet; import java.util.Set;  import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table;  import org.hibernate.validator.constraints.NotEmpty;  @SuppressWarnings("serial") @Entity @Table(name="APP_USER") public class User implements Serializable{      @Id @GeneratedValue(strategy=GenerationType.IDENTITY)     private Integer id;      @NotEmpty     @Column(name="SSO_ID", unique=true, nullable=false)     private String ssoId;      @NotEmpty     @Column(name="PASSWORD", nullable=false)     private String password;      @NotEmpty     @Column(name="FIRST_NAME", nullable=false)     private String firstName;      @NotEmpty     @Column(name="LAST_NAME", nullable=false)     private String lastName;      @NotEmpty     @Column(name="EMAIL", nullable=false)     private String email;      @NotEmpty     @ManyToMany(fetch = FetchType.LAZY)     @JoinTable(name = "APP_USER_USER_PROFILE",               joinColumns = { @JoinColumn(name = "USER_ID") },               inverseJoinColumns = { @JoinColumn(name = "USER_PROFILE_ID") })     private Set<UserProfile> userProfiles = new HashSet<UserProfile>();      public Integer getId() {         return id;     }      public void setId(Integer id) {         this.id = id;     }      public String getSsoId() {         return ssoId;     }      public void setSsoId(String ssoId) {         this.ssoId = ssoId;     }      public String getPassword() {         return password;     }      public void setPassword(String password) {         this.password = password;     }      public String getFirstName() {         return firstName;     }      public void setFirstName(String firstName) {         this.firstName = firstName;     }      public String getLastName() {         return lastName;     }      public void setLastName(String lastName) {         this.lastName = lastName;     }      public String getEmail() {         return email;     }      public void setEmail(String email) {         this.email = email;     }      public Set<UserProfile> getUserProfiles() {         return userProfiles;     }      public void setUserProfiles(Set<UserProfile> userProfiles) {         this.userProfiles = userProfiles;     }      @Override     public int hashCode() {         final int prime = 31;         int result = 1;         result = prime * result + ((id == null) ? 0 : id.hashCode());         result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode());         return result;     }      @Override     public boolean equals(Object obj) {         if (this == obj)             return true;         if (obj == null)             return false;         if (!(obj instanceof User))             return false;         User other = (User) obj;         if (id == null) {             if (other.id != null)                 return false;         } else if (!id.equals(other.id))             return false;         if (ssoId == null) {             if (other.ssoId != null)                 return false;         } else if (!ssoId.equals(other.ssoId))             return false;         return true;     }      /*      * DO-NOT-INCLUDE passwords in toString function.      * It is done here just for convenience purpose.      */     @Override     public String toString() {         return "User [id=" + id + ", ssoId=" + ssoId + ", password=" + password                 + ", firstName=" + firstName + ", lastName=" + lastName                 + ", email=" + email + "]";     }  } 

I am also using the same model provided in the demo. I didn't change anything in the model also not change related to jsp and controller. I don't understand why I am getting an error I am using the same way as like in a demo.

User profile

package com.websystique.springmvc.model;  import java.io.Serializable;  import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table;  @SuppressWarnings("serial") @Entity @Table(name="USER_PROFILE") public class UserProfile implements Serializable{      @Id @GeneratedValue(strategy=GenerationType.IDENTITY)     private Integer id;       @Column(name="TYPE", length=15, unique=true, nullable=false)     private String type = UserProfileType.USER.getUserProfileType();      public Integer getId() {         return id;     }      public void setId(Integer id) {         this.id = id;     }      public String getType() {         return type;     }      public void setType(String type) {         this.type = type;     }      @Override     public int hashCode() {         final int prime = 31;         int result = 1;         result = prime * result + ((id == null) ? 0 : id.hashCode());         result = prime * result + ((type == null) ? 0 : type.hashCode());         return result;     }      @Override     public boolean equals(Object obj) {         if (this == obj)             return true;         if (obj == null)             return false;         if (!(obj instanceof UserProfile))             return false;         UserProfile other = (UserProfile) obj;         if (id == null) {             if (other.id != null)                 return false;         } else if (!id.equals(other.id))             return false;         if (type == null) {             if (other.type != null)                 return false;         } else if (!type.equals(other.type))             return false;         return true;     }      @Override     public String toString() {         return "UserProfile [id=" + id + ", type=" + type + "]";     } } 

user profile converter

package com.websystique.springmvc.converter;  import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component;  import com.websystique.springmvc.model.UserProfile; import com.websystique.springmvc.service.UserProfileService;  /**  * A converter class used in views to map id's to actual userProfile objects.  */ @Component public class RoleToUserProfileConverter implements Converter<Object, UserProfile>{      static final Logger logger = LoggerFactory.getLogger(RoleToUserProfileConverter.class);      @Autowired     UserProfileService userProfileService;      /**      * Gets UserProfile by Id      * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)      */     public UserProfile convert(Object element) {         Integer id = Integer.parseInt((String)element);         UserProfile profile= userProfileService.findById(id);         logger.info("Profile : {}",profile);         return profile;     }  } 

Updated

one more thing while I printing the form data using model getter method getUserProfiles() I am getting blank data so I think it's not binding the selected value.but any other column I am printing it will perfectly bind.

1 Answers

Answers 1

After your comment I updated my reply:

Probably the problem is in JSP code. When application invokes the saveUser() method in your controller, a new User object is created. But because you have UserProfile type in User object the application has to know how to create UserProfile from String (when passed from <form:select path="userProfiles">).

Either you add a custom converter from String to UserProfile or create an UserDTO class with Java standard types and use it in your Controller save operation. Code will be something similar to:

public String saveUser(@Valid UserDTO dto, ...) {     User user = createUserFromDTO(dto);     userService.saveUser(user); } 

Also make sure, that you have the UserProfile entity correctly defined with JPA annotations.

Read More

Sunday, April 1, 2018

Spring disable @EnableResourceServer

Leave a Comment

I have resource server, when it's starts - it's sending request to Authentication server ("http://localhost:xxxx/auth/oauth/token_key"), and it's okay when all up and running.

But when I testing my services I do not need this at all. How can I disable resource server or maybe I should mock something so it won't be dependent on auth server(for future security tests for controllers)?

My spring boot main:

@SpringBootApplication @EnableEurekaClient @EnableResourceServer public class CalendarApplication {      public static void main(String[] args) throws Exception {         SpringApplication.run(CalendarApplication.class, args);     } } 

application.yml

security:   basic:     enabled: false   oauth2:     resource:       jwt:         keyUri: http://localhost:xxxx/auth/oauth/token_key 

Test class annotations:

@RunWith(SpringJUnit4ClassRunner.class) @WebMvcTest(value = TypeController.class, secure = false) public class TypeControllerTest {} 

3 Answers

Answers 1

Why don't you create a separate @Configuration for your @AuthenticationServer with a separate profile (@Profile("test"))? That way, you don't need to disable security and can have an in-memory Token. That's how I dealt with it. You can also disable Spring Security for your tests completely. Have a look at this question.

Answers 2

You can use @WithMockUser for tests

Testing Method Security

Answers 3

The way I've worked around this was to create a token in the database I'm using for test and to ensure that requests to my API used the token before making a request to the resource under test.

You do want your token there, since it acts as a reasonable sanity check for security. If you expect this resource to not be accessible without a specific token, then that is a useful test to have.

Read More

Tuesday, March 27, 2018

JavaConfig format of TransportGuarantee.CONFIDENTIAL related code for Tomcat 8.5

Leave a Comment

My goal is to have my Tomcat 8.5 application serve pages soley through https. In my ApplicationInitializer, I have this block of code:

ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(rootContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/");  if (Environment.PRODUCTION.getValue().equals(EnvironmentUtil.getEnvironmentName())) { //checked that the flow of control reaches here.  yes, I know it should be using spring profiles instead    HttpConstraintElement forceHttpsConstraint = new HttpConstraintElement(TransportGuarantee.CONFIDENTIAL);    ServletSecurityElement securityElement = new ServletSecurityElement(forceHttpsConstraint);            dispatcher.setServletSecurity(securityElement); } 

However, now I can't get the same effect unless I specifically add this to the web.xml:

<security-constraint>     <web-resource-collection>         <web-resource-name>Automatic Forward to HTTPS/SSL         </web-resource-name>         <url-pattern>/*</url-pattern>     </web-resource-collection>     <user-data-constraint>         <transport-guarantee>CONFIDENTIAL</transport-guarantee>     </user-data-constraint> </security-constraint> 

Are these two blocks equivalent? If so, why would the latter work and not the former?

I am trying to figure out why this would be the case. We recently switched from Tomcat 8 to Tomcat 8.5, so wondering whether that would be the issue. We also upgraded from Spring 4.3.11 to 4.3.14, but I don't know whether that would cause it either.

0 Answers

Read More

Friday, March 2, 2018

Spring Security Initialization throwing UnsatisfiedDependencyException on mvcContentNegotiationManager

Leave a Comment

I am trying to implement Spring Security 5.0.0.RELEASE in an existing Spring MVC project. Note that it is entirely Annotation Based.

Following is the code for my WebAppInitializer :

package com.abc.webapp.core;  public class WebAppInitializer implements WebApplicationInitializer{     @Override     public void onStartup(ServletContext container) throws ServletException {         AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();         context.setConfigLocation("com.abc.webapp.config");         container.addListener(new ContextLoaderListener(context));         ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcherServlet",                 new DispatcherServlet(context));         dispatcher.setLoadOnStartup(1);         dispatcher.addMapping("/");     } } 

Following is the WebMVCConfig File -

package com.abc.webapp.config;  @EnableWebMvc @Configuration @ComponentScan(basePackages = { "com.abc.webapp.controller" }) public class AppContextWebConfig extends WebMvcConfigurerAdapter {      @Bean     public InternalResourceViewResolver resolver() {         InternalResourceViewResolver resolver = new InternalResourceViewResolver();         resolver.setViewClass(JstlView.class);         resolver.setPrefix("/WEB-INF/views/");         resolver.setSuffix(".jsp");         return resolver;     }      @Override     public void addResourceHandlers(ResourceHandlerRegistry registry) {         registry.addResourceHandler("/resources/css/**").addResourceLocations("/WEB-INF/css/");         registry.addResourceHandler("/resources/js/**").addResourceLocations("/WEB-INF/js/");     } } 

Now as per the Spring Security Docs I am trying to configure like following -

package com.abc.webapp.config;  @EnableWebSecurity @Configuration public class AppContextSecurityConfig extends WebSecurityConfigurerAdapter{      @Autowired     public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {         auth.inMemoryAuthentication().                 withUser(User.withDefaultPasswordEncoder()                         .username("user")                         .password("password")                         .roles("USER")                 );     }      @Override     protected void configure(HttpSecurity http) throws Exception {        // Code for Login URL and Logout URL      } } 

And

package com.abc.webapp.core;  public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer{  } 

When I am trying to start the server I am getting the following stacktrace -

[ERROR][2018-01-30 01:40:13 ContextLoader:351] - Context initialization failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'appContextSecurityConfig': Unsatisfied dependency expressed through method 'setContentNegotationStrategy' parameter 0: Error creating bean with name 'mvcContentNegotiationManager' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.accept.ContentNegotiationManager]: Factory method 'mvcContentNegotiationManager' threw exception; nested exception is java.lang.AbstractMethodError; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mvcContentNegotiationManager' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.accept.ContentNegotiationManager]: Factory method 'mvcContentNegotiationManager' threw exception; nested exception is java.lang.AbstractMethodError         at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:651)         at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)         at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350)         at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)         at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) 

I am quite sure I am not missing any steps mentioned in the Srping setup. I have googled several times but of no use. I am also tried removing the SecurityWebAppInitializer and manually adding the filter in the WebAppInitializer like the following way.

FilterRegistration.Dynamic  springSecurityFilterChain = container.addFilter("springSecurityFilterChain", DelegatingFilterProxy.class); springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*"); 

And I am still getting the exception during startup. Any clues or solutions are highly appreciated.

1 Answers

Answers 1

It might be due to an incompatibility of your spring-web-X.X.X.RELEASE.jar , Spring Data Commons jar. Please check spring jar versions using following command

mvn dependency:tree. 
Read More

Friday, February 9, 2018

SAML Http Request Intercept with Spring Boot

Leave a Comment

In reference to this SO question Add request parameter to SAML request using Spring Security SAML

I am wanting to replace the default HTTPRedirectDeflateBinding bean with my own that has a custom HTTPRedirectDeflateEncoder to add query params to my SAML request.

I'm trying to achieve this with the Spring Boot @Bean auto-configuration annotation and being new to the Java environment I can't seem to get it working right. I can see that my bean is registering on startup but the outbound HTTP request is not being intercepted by it and it appears the original redirectBinding still is.

Here is my bean I added into my Configuration class:

@Bean(name="redirectBinding") @Primary public HTTPRedirectDeflateBinding HTTPRedirectDeflateBinding() {     return new HTTPRedirectDeflateBinding(null, new My_SAML_HttpRedirectDeflateEncoder()); } 

Here is my encoder I'm trying to pass into the redirect binding

public class My_SAML_HttpRedirectDeflateEncoder extends HTTPRedirectDeflateEncoder{  @Override protected String buildRedirectURL(SAMLMessageContext messagesContext, String endpointURL, String message)         throws MessageEncodingException {     URLBuilder urlBuilder = new URLBuilder(endpointURL);     List<Pair<String, String>> queryParams = urlBuilder.getQueryParams();      if (messagesContext.getOutboundSAMLMessage() instanceof RequestAbstractType) {         queryParams.add(new Pair<String, String>("service", "myService"));         queryParams.add(new Pair<String, String>("serviceType", "dev"));     }      return urlBuilder.buildURL(); } 

}

I also attempted the solution proposed from this SO response spring boot adding http request interceptors Similar results, my HandlerInterceptor bean was registered but nothing is being intercepted. I feel like I'm missing a small detail. Any help would be appreciated.

1 Answers

Answers 1

You can redeclare the SAMLProcessor bean - which is used by SAMLProcessingFilter - and add your own binding bean in its bindings list. This is an example, I used in my project.

@Bean public SAMLProcessorImpl processor() {     Collection<SAMLBinding> bindings = new ArrayList<>();     bindings.add(httpRedirectDeflateBinding());     bindings.add(httpPostBinding());     bindings.add(artifactBinding(parserPool(), velocityEngine()));     bindings.add(httpSOAP11Binding());     bindings.add(httpPAOS11Binding());      return new SAMLProcessorImpl(bindings); } 

Hope it works for you.

Read More

Thursday, January 18, 2018

Spring boot use resources templates folder with JSP templates instead of webapp folder?

Leave a Comment

I started a Spring Boot MVC project and realized that there are two folder withing resources. One is called templates and the other static. I really like this folder setup.r

The problem is that I use JSP Templates for my views. I could not place a .jsp template inside the templates folder and got it to work. What I needed to do is to create a webapp folder on the same level as src and resources. Placing my JSP templates in there and then my views can be found.

What do I need to reconfigure to actually use my JSP templates within the templates folder which lies within resources?

3 Answers

Answers 1

Official information:

Resource handling:

Links to resources are rewritten at runtime in template, thanks to a ResourceUrlEncodingFilter, auto-configured for Thymeleaf and FreeMarker. You should manually declare this filter when using JSPs. source

Supported template engine

As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. Spring MVC supports a variety of templating technologies including Thymeleaf, FreeMarker and JSPs.

[...]

JSPs should be avoided if possible, there are several known limitations when using them with embedded servlet containers.

[..]

When you’re using one of these templating engines with the default configuration, your templates will be picked up automatically from src/main/resources/templates.

source

Spring boot JSP limitations

  • With Tomcat it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to a standard
    container (not limited to, but including Tomcat).
  • An executable jar will not work because of a hard coded file pattern in Tomcat.
  • With Jetty it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to any standard container.
  • Undertow does not support JSPs.
  • Creating a custom error.jsp page won’t override the default view for error handling, custom error pages should be used instead.

source

Technical change

Tell spring boot to from where to load the JSP files. In application.properties set

spring.mvc.view.prefix: /WEB-INF/views/ spring.mvc.view.suffix: .jsp 

source

Sample spring boot with JSP

In case you do want to use JSP with spring boot here are two examples:

https://github.com/spring-projects/spring-boot/tree/v1.5.9.RELEASE/spring-boot-samples/spring-boot-sample-web-jsp

https://github.com/joakime/spring-boot-jsp-demo

Answers 2

To summarize it, none of the suggested answers worked for me so far. Using a blank Spring boot starter project.

Somehow, something looks hardwired inside Spring or servlets so that JSP must be in /webapp (or a subfolder). Unlike default thymeleaf templates which are looked up in /resources/templates.

I tried all kind of changes, really a lot of different configurations, but wasn't able to modify that behavior. It just produced complexity and was unable to serve the JSPs anymore. So, bottom line, if you're using JSPs, just put them in /webapp. It also works by addding zero configuration using a controller like:

@GetMapping("/foo") public String serveFoo() { return "relative-path-inside-webapp/foo.jsp"; }

On another note, by default, the /webapp folder will also be hidden in the Spring Toolsuite, so you'll have to manually configure it as a "source folder".

Answers 3

According to the Maven documentation src/main/resources will end up in WEB-INF/classes in the WAR.

This does the trick for Spring Boot in your application.properties:

spring.mvc.view.prefix = /WEB-INF/classes/templates spring.mvc.view.suffix = .jsp 

If you prefer Java configuration this is the way to go (I tested this with a sample project here):

@EnableWebMvc @Configuration public class ApplicationConfiguration extends WebMvcConfigurerAdapter {      @Bean     public ViewResolver jspViewResolver() {         InternalResourceViewResolver bean = new InternalResourceViewResolver();         bean.setPrefix("/WEB-INF/classes/templates/");         bean.setSuffix(".jsp");         return bean;     } } 
Read More

Monday, December 4, 2017

Unable to upload picture from Android to java server

Leave a Comment

I've been trying to implement profile photo upload feature by Android Retrofit + SpringMVC. Java server unable to respond Retrofit API call. Related code snippet is given below:

ApiInterface

@Multipart @POST("user/profileImage") Call<ResponseBody> uploadImage(@Part MultipartBody.Part image, @Part("name") RequestBody name); 

uploadToServer

public void uploadToServer(){     //Get retrofit client     Retrofit retrofit = ApiClient.getClient();     //Get API interface     ApiInterface apiInterface = retrofit.create(ApiInterface.class);     // Get image parts     MultipartBody.Part imageParts = bitmapToMultipart(imageBitmap);     //Get image name     RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "ProfileImage");     //Call image upload API     Call<ResponseBody> call = apiInterface.uploadImage(imageParts,name);     call.enqueue(new Callback<ResponseBody>() {         @Override         public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {             ResponseBody body = response.body();         }          @Override         public void onFailure(Call<ResponseBody> call, Throwable t) {             t.printStackTrace();         }     }); } 

bitmapToMultipart

public MultipartBody.Part bitmapToMultipart(Bitmap imageBitmap){     File file = null;     try {         //create a file to write bitmap data         file = new File(this.getCacheDir(), "imageBitmap");         file.createNewFile();          //Convert bitmap to byte array         ByteArrayOutputStream bos = new ByteArrayOutputStream();         imageBitmap.compress(Bitmap.CompressFormat.JPEG, 0 /*ignored for PNG*/, bos);         byte[] bitmapdata = bos.toByteArray();          //write the bytes in file         FileOutputStream fos = new FileOutputStream(file);         fos.write(bitmapdata);         fos.flush();         fos.close();     }catch(IOException e){         e.printStackTrace();     }     RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);     MultipartBody.Part body = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);      return body; } 

Java SpringMVC controller

@Controller @RequestMapping("/user") public class UserController{     @RequestMapping(value = "/profileImage", method = RequestMethod.POST)     public  @ResponseBody String imageUploader(@RequestParam("image") MultipartFile image, @RequestBody RequestBody name)throws Exception{         return "";     } } 

Problem is: Request not even reaching to java server.

4 Answers

Answers 1

In your uploadToServer() function media type should be "multipart/form-data" in place of "text/plain" for field name...

//Get image name     RequestBody name = RequestBody.create(MediaType.parse("multipart/form-data"), "ProfileImage"); 

In your bitmapToMultipart() function media type should be "multipart/form-data". ("image/*" should also work but if not "multipart/form-data" will definitely work)

refer - How to Upload Image file in Retrofit 2

And in your spring controller you should use @RequestParam in place of @Requestbody

@Controller @RequestMapping("/user") public class UserController{     @RequestMapping(value = "/profileImage", method = RequestMethod.POST)     public  @ResponseBody String imageUploader(@RequestParam("image") MultipartFile image, @RequestParam String name)throws Exception{         return "";     } } 

Answers 2

Please change your

RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file); 

to

RequestBody reqFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); 

ie you bitmapToMultipart function should be like,

public MultipartBody.Part bitmapToMultipart(Bitmap imageBitmap){     File file = null;     try {         //create a file to write bitmap data         file = new File(this.getCacheDir(), "imageBitmap");         file.createNewFile();          //Convert bitmap to byte array         ByteArrayOutputStream bos = new ByteArrayOutputStream();         imageBitmap.compress(Bitmap.CompressFormat.JPEG, 0 /*ignored for PNG*/, bos);         byte[] bitmapdata = bos.toByteArray();          //write the bytes in file         FileOutputStream fos = new FileOutputStream(file);         fos.write(bitmapdata);         fos.flush();         fos.close();     }catch(IOException e){         e.printStackTrace();     }     RequestBody reqFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);     MultipartBody.Part body = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);      return body; } 

Answers 3

ApiInterface

@Multipart @POST("user/profileImage") Call<ResponseBody> uploadImage(@Part("image") MultipartBody.Part image, @Part("name") RequestBody name); 

uploadToServer

public void uploadToServer(){     //Get retrofit client     Retrofit retrofit = ApiClient.getClient();     //Get API interface     ApiInterface apiInterface = retrofit.create(ApiInterface.class);     // Get image parts     MultipartBody.Part imageParts = bitmapToMultipart(imageBitmap);     //Get image name     RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "ProfileImage");     //Call image upload API     Call<ResponseBody> call = apiInterface.uploadImage(imageParts,name);     call.enqueue(new Callback<ResponseBody>() {         @Override         public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {             ResponseBody body = response.body();         }          @Override         public void onFailure(Call<ResponseBody> call, Throwable t) {             t.printStackTrace();         }     }); } 

bitmapToMultipart

public MultipartBody.Part bitmapToMultipart(Bitmap imageBitmap){          ByteArrayOutputStream bos = new ByteArrayOutputStream();         imageBitmap.compress(Bitmap.CompressFormat.JPEG, 0 /*ignored for PNG*/, bos);         byte[] bitmapdata = bos.toByteArray();      RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), bitmapdata);     MultipartBody.Part body = MultipartBody.Part.createFormData("upload", "name", reqFile);      return body; }   

Java SpringMVC controller

@Controller @RequestMapping("/user") public class UserController{     @RequestMapping(value = "/profileImage", method = RequestMethod.POST)     public  @ResponseBody String imageUploader(@RequestParam("image") MultipartFile image, @RequestParam String name)throws Exception{         return "";     } } 

Answers 4

  1. first you should check android client upload file is OK.eg:use compress quality 80

    imageBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);

  2. change MediaType and debug at client RequestBody have data
  3. Debug at server check receive request data
Read More

Sunday, November 26, 2017

Why do accountExpires and userAccountControl filters in SpringLDAP / plain Java AD queries do not work as expected?

Leave a Comment

I'm using SpringLDAP API within spring based webapp to query ActiveDirectory that is hosted on Windows Server 2012. Following are my environment details :- Java 1.8.0_101, apache-tomcat-8.0.36, SpringMVC 4.3.1 & SpringLDAP 2.3.1

The following AD filter query works in windows based (may be C++/C#) query tool (e.g., Lepide AD Query tool) and also in the LDAP Browser plugin within the eclipse IDE but does not work within the Java (JNDI/SpringLDAP API based) code & in the Java based application JXplorer :-

(&(objectclass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(accountExpires>=131554368000000000)(userPrincipalName=cgm@*)) 

I'm trying to get an user account that is ACTIVE, not yet expired given a date and with userPrincipalName value starting with string cgm@.

Following is the ldap configuration within the spring-servlet.xml file :-

<util:map id="ldapBaseEnvProps">         <entry key="java.naming.ldap.attributes.binary" value="objectGUID"/> </util:map> <ldap:context-source id="pooledLdapContextSrc" url="ldap://dc.myadserver.com:3268" base="DC=myadserver,DC=com" username="CN=adusername,OU=Mkt-Managers,DC=myadserver,DC=com" password="*****" base-env-props-ref="ldapBaseEnvProps">     <ldap:pooling max-total="16" max-active="16" max-idle="8" min-idle="0" max-wait="90000" when-exhausted="BLOCK" test-on-borrow="true" test-while-idle="true"/> </ldap:context-source> 

Are such AD filters supported by Java/SpringLDAP API at all? If yes, what needs to be changed for the above AD query filter to work in the Java based code?

1 Answers

Answers 1

I would suggest using Spring LDAP's query builder object in Java to help you build that query. Your question seems to indicate that you copied that query from your C (windows) environment into your Java environment.

I would start by building the query with .where() function in Spring LDAP as used here and seeing if it results in the same error: https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/query/LdapQueryBuilder.html

Read More

Wednesday, November 15, 2017

Spring Security - multiple configurations - add LogoutHandler

Leave a Comment

I have a spring-boot application using spring-security. The security configuration is split into multiple instances of WebSecurityConfigurerAdapter.

I have one where I configure logout in general:

@Override protected void configure(HttpSecurity http) throws Exception {      // configure logout     http             .logout()             .logoutUrl("/logout")             .invalidateHttpSession(true)             .addLogoutHandler((request, response, authentication) -> {                 System.out.println("logged out 1!");             })             .permitAll();      // ... more security configuration, e.g. login, CSRF, rememberme } 

And there is another WebSecurityConfigurerAdapter, where I want to do almost nothing, except adding another LogoutHandler:

@Override protected void configure(HttpSecurity http) throws Exception {      // configure logout     http             .logout()             .logoutUrl("/logout")             .addLogoutHandler((request, response, authentication) -> {                 System.out.println("logged out 2!");             }); } 

Both configure() methods are called. However, if I do log out, only the first LogoutHandler is called. Changing the @Order of both configurations does not change the result.

What is missing in my configuration?

3 Answers

Answers 1

When you create several security configurations Spring Boot will create a separate SecurityFilterChain for each of them. See WebSecurity:

@Override protected Filter performBuild() throws Exception {     // ...     for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {         securityFilterChains.add(securityFilterChainBuilder.build());     }     // ... } 

When application gets logout request FilterChainProxy will return only one SecurityFilterChain:

private List<Filter> getFilters(HttpServletRequest request) {     for (SecurityFilterChain chain : filterChains) {         // Only the first chain that matches logout request will be used:         if (chain.matches(request)) {             return chain.getFilters();         }     }      return null; } 

If you really need modular security configuration I would suggest to create a separate security configuration for logout and other realms. You can define logout handlers as beans (using @Bean annotation) in different configuration classes and collect these handlers in logout configuration:

WebSecurityLogoutConfiguration.java

@Configuration @Order(99) public class WebSecurityLogoutConfiguration extends WebSecurityConfigurerAdapter {      // ALL YOUR LOGOUT HANDLERS WILL BE IN THIS LIST     @Autowired     private List<LogoutHandler> logoutHandlers;      @Override     protected void configure(HttpSecurity http) throws Exception {         // configure only logout         http                 .logout()                 .logoutUrl("/logout")                 .invalidateHttpSession(true)                 // USE CompositeLogoutHandler                 .addLogoutHandler(new CompositeLogoutHandler(logoutHandlers));         http.csrf().disable(); // for demo purposes     } } 

WebSecurity1Configuration.java

@Configuration @Order(101) public class WebSecurity1Configuration extends WebSecurityConfigurerAdapter {      @Override     protected void configure(HttpSecurity http) throws Exception {         // ... more security configuration, e.g. login, CSRF, rememberme         http.authorizeRequests()                 .antMatchers("/secured/**")                 .authenticated();     }      // LOGOUT HANDLER 1     @Bean     public LogoutHandler logoutHandler1() {         return (request, response, authentication) -> {             System.out.println("logged out 1!");         };     } } 

WebSecurity2Configuration.java

@Configuration @Order(102) public class WebSecurity2Configuration extends WebSecurityConfigurerAdapter {      @Override     protected void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                 .antMatchers("/api/**")                 .permitAll();     }      // LOGOUT HANDLER 2     @Bean     public LogoutHandler logoutHandler2() {         return (request, response, authentication) -> {             System.out.println("logged out 2!");         };     } } 

Answers 2

You should be solving this problem with the CompositeLogoutHandler on your single /logout operation endpoint.

You can still keep two WebSecurityConfigurerAdapter's as desired, but you'll be conglomerating the logout functionality for two LogoutHandlers into a single composite action:

new CompositeLogoutHandler(loggedOutHandler1, loggedOutHandler2); 

Answers 3

The keypoint is you should create separated instance of AuthenticationManger.

Here is an sample for multiples WebSecurityAdapter

Read More

Monday, October 23, 2017

How a jar can propagate a vulnerability in a web application where it is used?

Leave a Comment

I have a Spring MVC web application protected with Spring Security. Life seems so calm until I was forced to do a Static Application Security Testing (SAST) and the tool threw a bunch of security issues. Have a look at here:

enter image description here

I have gone through all CVEs and got a rough picture about the vulnerabilities. I have a few queries:

  1. How a web application is vulnerable to such exploitation, when a security framework like (Spring Security) is integrated with it?

  2. Can I ignore all those vulnerabilities since Spring Security might have some sort of workaround for all those vulnerabilities?

1 Answers

Answers 1

From the Spring Security manual:

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.

Think of spring security as an authentication framework, it covers one piece of the security puzzle.

As an example, let's have a look at the #1 of the OWASP Top 10 Application Security Risks: A1 - Injection
Assume you use a jar for accessing an SQL database (e.g. hibernate) and it has an injection vulnerability, then your application could be vulnerable as well. However even if hibernate doesn't have any security bugs, if a programmer concatenates an SQL query together without correctly escaping the user input the application is vulnerable to an injection attack.
Spring security doesn't protect your application from either of these injection attacks.

If a jar has a vulnerability and you are calling the vulnerable methods/features then your app may also have that vulnerability, it depends a lot on what the vulnerability is and how its executed and how your application is configured to use the jar.

For a quick look over the other OWASP Top 10 Application Security Risks:
A1-Injection - No protection from Spring Security
A2-Broken Authentication and Session Management - Spring Security can help manage some of these, however a miss configured spring security will expose these.
A3-Cross-Site Scripting (XSS) - No protection from Spring Security
A4-Insecure Direct Object References - No added protection from Spring Security (Spring Security gives you the tool to manage this)
A5-Security Misconfiguration - No protection from Spring Security
A6-Sensitive Data Exposure - Spring Security can assist with this however it also depends a lot on how you store and manage your data (E.g. log files)
A7-Missing Function Level Access Control - If the access control has been missed, Spring Security can't help you, however spring security makes it easy to add these
A8-Cross-Site Request Forgery (CSRF) - Spring Security (depending on how your application is configured) will assist you or even manage this risk for you.
A9-Using Components with Known Vulnerabilities - This is the CVE's you have listed in your question - No protection from Spring Security
A10-Unvalidated Redirects and Forwards - Spring Security could be used to manage this however it doesn't protect your application from this out of the box

The list of CVEs found during the STAT of your application is an example of A9-Using Components with Known Vulnerabilities have a look at the OWASP wiki for more information.

Example Attack Scenarios

Component vulnerabilities can cause almost any type of risk imaginable, ranging from the trivial to sophisticated malware designed to target a specific organization. Components almost always run with the full privilege of the application, so flaws in any component can be serious, The following two vulnerable components were downloaded 22m times in 2011.

  • Apache CXF Authentication Bypass – By failing to provide an identity token, attackers could invoke any web service with full permission. (Apache CXF is a services framework, not to be confused with the Apache Application Server.)
  • Spring Remote Code Execution – Abuse of the Expression Language implementation in Spring allowed attackers to execute arbitrary code, effectively taking over the server.

Every application using either of these vulnerable libraries is vulnerable to attack as both of these components are directly accessible by application users. Other vulnerable libraries, used deeper in an application, may be harder to exploit.

Note from the last paragraph above, the deeper the component (jar) is the harder it is to exploit, however, that doesn't mean a determined entity can't exploit them.

In summary, Spring Security is a great tool for managing authentication and access-controls in your application but it isn't a magic bullet to fix all security problems.

Read More

Monday, October 2, 2017

Can Spring be directed to take a parameter from either the body or the URL?

Leave a Comment

An argument to a Spring MVC method can be declared as RequestBody or RequestParam. Is there a way to say, "Take this value from either the body, if provided, or the URL parameter, if not"? That is, give the user flexibility to pass it either way which is convenient for them.

2 Answers

Answers 1

You can make both variables and check them both for null later on in your code like this :

@RequestMapping(value = GET_SOMETHING, params = {"page"}, method = RequestMethod.GET) public @ResponseBody JSONObject getPromoByBusinessId(         @PathVariable("businessId") String businessId, @RequestParam("page") int page,         @RequestParam("valid") Boolean valid,         @RequestParam("q") String promoName) throws Exception {} 

and then use a series if if-else to react to requests. I wrote it to work with any of the three params be null or empty, react to all different scenarios.

To make them optional, see : Spring Web MVC: Use same request mapping for request parameter and path variable

Answers 2

HttpServletRequest interface should help solve this problem

@RequestMapping(value="/getInfo",method=RequestMethod.POST) @ResponseBody public String getInfo(HttpServletRequest request) {     String name=request.getParameter("name");     return name;  } 

Now, based on request data coming from body or parameter the value will be picked up

C:\Users\sushil λ curl http://localhost:8080/getInfo?name=sushil-testing-parameter sushil-testing-parameter C:\Users\sushil λ curl -d "name=sushil-testing-requestbody" http://localhost:8080/getInfo sushil-testing-requestbody C:\Users\sushil λ 
Read More

Thursday, September 21, 2017

Spring MVC - Drop Down Object Selection - No primary identifier

Leave a Comment

A fairly common use case occurs where there is a list of Java objects, from which selections can be made on a web form - usually you'd use the primary key of the object as the value so that the controller could either do a lookup, or just bind the key to whichever object is created/updated.

My problem is that the list to choose from are not persistent, keyed objects, they are business models from a service which have no reasonable way to retrieve them based on the data contained. Below is some psuedo code where a list of Foo's are given to the page, and we can easily communicate to the controller onSubmit the name of Foo, but what if there are other fields of Foo that need to be submitted?

controller:

referenceData() {     ...     List foos = fooService.getFoosForBar( bar )     return { 'foos', foos } } 

jsp:

<form>    ... <spring:bind path="formData.foo">     <select name="<c:out value="${status.expression}" />">         <c:forEach items="${foos}" var="foo">             <option value="<c:out value="${foo.name}"/>">                 <c:out value="${foo.name}"/>             </option>         </c:forEach>     </select> </spring:bind>    ... </form> 

Some example solutions would be to use hidden fields to submit Foo's other properties and keep them in sync as the selection is changed, but I prefer not to use JavaScript in a situation like this where it will likely add confusion. There are certainly other ways to accomplish this too.

My question is does there exist any standard practice for accomplishing this? Or should I just come up with my own way of doing so? I'd rather not re-invent wheels if possible, and this is so seemingly common that just winging it may not be the best approach.

2 Answers

Answers 1

Based on your limitations, you must encode the other data memebers of foos as the value of the option.
<option label="${foo.name}" value="${foo.encodedValues}"/>
The encodedValues method might look something like this:

      private String SEPERATOR = ",";      public String getEncodedValues()     {         StringBuffer returnValue = new StringBuffer();          returnValue.append(field1);         returnValue.append(SEPERATOR);         returnValue.append(field2);         returnValue.append(SEPERATOR);         returnValue.append(field3);          return returnValue.toString();     }  

If you have a number of selects that need to have encoded values, you may want to create a class that does the encoding and decoding of these values to centralize the code.

Answers 2

You can use the index of the element in the list to get it back in the POST request.

<spring:bind path="formData.fooIndex">   <select name="<c:out value="${status.expression}" />">     <c:forEach items="${foos}" var="foo" varStatus="i">         <option value="<c:out value="${i.index}"/>">             <c:out value="${foo.name}"/>         </option>     </c:forEach>   </select> </spring:bind> 

In your POST handler, use foos.get(formData.getFooIndex()) If foos can change between the GET and POST requests, you need to put foos in session so that you definitely reference the same object in your POST handler as you did in the GET handler.

Read More

Tuesday, September 19, 2017

Spring security check if user has access to mentioned url

Leave a Comment

I have started using spring security, and after a lot of research I am not able to find an answer for:

If I explicitly want to check if user A have access to stuff B. I can check this with JSP tag support Spring Security - check if web url is secure / protected like

<sec:authorize url="stuff/B"> 

But what if I want to check the same thing in the controller(java class). I am not finding any spring function here to check if a login user has access to mentioned url(https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html)

6 Answers

Answers 1

Hint from the javadoc:

to use this tag there must also be an instance of WebInvocationPrivilegeEvaluator in your application context. If you are using the namespace, one will automatically be registered. This is an instance of DefaultWebInvocationPrivilegeEvaluator,"

And in the javadoc of DefaultWebInvocationPrivilegeEvaluator, we can see a isAllowed method that should do the job:

// privilegeEvaluator is a WebInvocationPrivilegeEvaluator "autowired" boolean allowed = privilegeEvaluator.isAllowed("/stuff/B", yourAuthentication); 

Answers 2

Why not to use annotations like this:

@PreAuthorize("hasRole('ROLE_USER')") public void create(Contact contact); 

Annotations are standard way for Spring 3+

Answers 3

You are looking at the right place, the link you attached mentions what you need. Since you want access-control on your controller and check per user (not role) you can use the '@PreAuthorize' annotation with "hasPermission" expression or similar.

You could check here for expression-based access control and here for examples of custom security expression example in case you want to customize the solution.

Answers 4

1) First we need to know whether the user may enter the URL at all. This can be very easily achieved using WebInvocationPrivilegeEvaluator.

privilegeEvaluator.isAllowed(contextPath, url, "GET", currentUser); 

2) Now we need to identifying whether the user may access the handler method

private boolean isAllowedByAnnotation(Authentication currentUser, HandlerMethod method) {     PreInvocationAuthorizationAdvice advice = new ExpressionBasedPreInvocationAdvice();     PreInvocationAuthorizationAdviceVoter voter = new PreInvocationAuthorizationAdviceVoter(advice);      MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();     PrePostInvocationAttributeFactory factory = new ExpressionBasedAnnotationAttributeFactory(expressionHandler);     PrePostAnnotationSecurityMetadataSource metadataSource = new PrePostAnnotationSecurityMetadataSource(factory);      Class<?> controller = method.getBeanType();     MethodInvocation mi = MethodInvocationUtils.createFromClass(controller, method.getMethod().getName());     Collection<ConfigAttribute> attributes = metadataSource.getAttributes(method.getMethod(), controller);      return PreInvocationAuthorizationAdviceVoter.ACCESS_GRANTED == voter.vote(currentUser, mi, attributes); } 

Answers 5

We can create a custom PermissionEvaluator and use

hasPermission(Authentication authentication, Object domainObject, Object permission).

  @Override   protected MethodSecurityExpressionHandler createExpressionHandler() {     final DefaultMethodSecurityExpressionHandler expressionHandler =         new DefaultMethodSecurityExpressionHandler();     expressionHandler.setPermissionEvaluator(new AclPermissionEvaluator(aclService()));     return expressionHandler;   }   @Bean   public aclServiceImpl aclService() {     final AclServiceImpl mutableAclService = new AclServiceImpl          (authorizationStrategy(), grantingStrategy());     return mutableAclService;   } 

AclServiceImpl is the implementation of MutableAclService

Answers 6

The most obviously useful annotation is @PreAuthorize which decides whether a method can actually be invoked or not. For example (from the"Contacts" sample application)

@PreAuthorize("hasRole('USER')") public void create(Contact contact); 

which means that access will only be allowed for users with the role "ROLE_USER". Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role. But what about:

@PreAuthorize("hasPermission(#contact, 'admin')") public void deletePermission(Contact contact, Sid recipient, Permission permission); 

Here we’re actually using a method argument as part of the expression to decide whether the current user has the "admin"permission for the given contact. The built-in hasPermission() expression is linked into the Spring Security ACL module through the application context.

For More Detailed Explanation please refer this Link

Read More