0

I have a Spring MVC web application protected with Spring Secuirty and it's configured using Java annotations, this is My Spring MVC application security config classes

package seguridad;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;



@Configuration
@EnableWebSecurity
//@EnableWebMvcSecurity

public class SeguridadConfiguracion extends WebSecurityConfigurerAdapter {

    @Autowired 
    private AutenticarProvider autenticador;

    @Override
    protected void configure( HttpSecurity http ) throws Exception 
    {
        http
            .authenticationProvider(autenticador)
            .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/css/**").permitAll() 
                .antMatchers("/js/**").permitAll()
                .antMatchers("/img/**").permitAll() 
                .antMatchers("/sound/**").permitAll() 
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/ajax/**").permitAll()
                .antMatchers("/php/**").permitAll()
                .antMatchers("/xml/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .loginPage("/login/login")
                    .permitAll()
                    .and()
                .logout()                                    
                    .permitAll()
                    .logoutSuccessUrl("/login/login?logout")
                .and()
                    .csrf().disable();
    }

}

My AuthProvider

@Component
public class AutenticarProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {

        String name = null;
        String password = null;
        Authentication auth = null;
        boolean pruebaLDAP = false;

        try {
            name = authentication.getName();
            password = authentication.getCredentials().toString();


            if (name.equals("user") && password.equals("MyPassword")) 
            {
                List<GrantedAuthority> grantedAuths = new ArrayList<>();
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_PRIMERO"));
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_MODIFICAR_PERMISO"));
                grantedAuths.add(new SimpleGrantedAuthority("PERMISO_CONSULTAR_PERMISO"));

                auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
            }

            } catch (AuthenticationException e) {
                e.printStackTrace();
                throw e;
            }

            return auth;
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return authentication.equals(UsernamePasswordAuthenticationToken.class);
        }

This is my Controller class of the Web service Restful method that I want to call, The method receive a JSON string then I retreive the values I want to from the JSON string and then assign those values to an POJO Object then return the Object

@Controller
@RequestMapping("/jsp/")
public class InicioControlador {



    @RequestMapping(value = "changeNameAfter", method = RequestMethod.POST)
    public @ResponseBody
    Person methodChangeStringPro(@RequestBody final String json, Model model)
            throws IOException {

        ObjectMapper mapper = new ObjectMapper();

        Map<String, String> StringValues;
        StringValues = mapper.readValue(json, HashMap.class);

        String stringId = StringValues.get("id");
        String name = StringValues.get("name");

        System.out.println("EL STRING ID vale " + stringId);
        System.out.println("EL name  vale " + name);

        int realId = Integer.parseInt(stringId);

        String newName = name + "KEK";
        realId = realId + 1;

        Person person = new Person();
        person.setName(newName);
        person.setId(realId);


        return person;
    }
}

And this is the code from My android app where I'm trying to call that method

My Main Activity class

public class MainActivity extends AbstractAsyncActivity {

protected static final String TAG = MainActivity.class.getSimpleName();

// ***************************************
// Activity methods
// ***************************************

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Initiate the request to the protected service
    final Button submitButton = (Button) findViewById(R.id.submit);
    submitButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            new FetchSecuredResourceTask().execute();
        }
    });
}

// ***************************************
// Private methods
// ***************************************
private void displayResponse(Person response) {
    Toast.makeText(this, response.getName(), Toast.LENGTH_LONG).show();
}

// ***************************************
// Private classes
// ***************************************
private class FetchSecuredResourceTask extends AsyncTask<Void, Void, Person> {

    private String username;

    private String password;

    @Override
    protected void onPreExecute() {
        showLoadingProgressDialog();

        // build the message object
        EditText editText = (EditText) findViewById(R.id.username);
        this.username = editText.getText().toString();

        editText = (EditText) findViewById(R.id.password);
        this.password = editText.getText().toString();
    }

    @Override
    protected Person doInBackground(Void... params) {
        final String url = "http://10.0.2.2:8080/ProyectoServidor/jsp/changeNameAfter";

        // Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());

        //Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");


        HttpEntity entityPerson = new HttpEntity(personToSend, requestHeaders);

        try {
            // Make the network request
            Log.d(TAG, url);
            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST,
                    entityPerson, Person.class);
            return response.getBody();
        } catch (HttpClientErrorException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        } catch (ResourceAccessException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        }
    }

    @Override
    protected void onPostExecute(Person result) {
        dismissProgressDialog();
        displayResponse(result);
    }

}

My AbstractAsyncActivity class

public class AbstractAsyncActivity extends Activity {

protected static final String TAG = AbstractAsyncActivity.class.getSimpleName();

private ProgressDialog progressDialog;

private boolean destroyed = false;

// ***************************************
// Activity methods
// ***************************************
@Override
protected void onDestroy() {
    super.onDestroy();
    destroyed = true;
}

// ***************************************
// Public methods
// ***************************************
public void showLoadingProgressDialog() {
    this.showProgressDialog("Loading. Please wait...");
}

public void showProgressDialog(CharSequence message) {
    if (progressDialog == null) {
        progressDialog = new ProgressDialog(this);
        progressDialog.setIndeterminate(true);
    }

    progressDialog.setMessage(message);
    progressDialog.show();
}

public void dismissProgressDialog() {
    if (progressDialog != null && !destroyed) {
        progressDialog.dismiss();
    }
}
}

I think that the problem are in this line from my Main Acitivity class

// Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());

        //Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");

        HttpEntity entityPerson = new HttpEntity(personToSend, requestHeaders);

        try {
            // Make the network request
            Log.d(TAG, url);
            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST,
                    entityPerson, Person.class);
            return response.getBody();
        } catch (HttpClientErrorException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        } catch (ResourceAccessException e) {
            Log.e(TAG, e.getLocalizedMessage(), e);
            return new Person();
        }

Since the ERROR that I'm getting in my LogCat is

10-16 00:33:51.054: E/AndroidRuntime(1481): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1]

I was following this tutorial but I adapted it for my needs https://github.com/spring-projects/spring-android-samples/tree/master/spring-android-basic-auth

I'm using the following libs

jackson-core-asl-1.9.11.jar
jackson-mapper-asl-1.9.13.jar
spring-android-core-1.0.0.RELEASE.jar
spring-android-rest-template-1.0.1.RELEASE.jar

EDIT User @ravindra the classNotFoundError was because I used jackson-core-asl-1.9.11.jar instead of jackson-core-2.6.1.jar after I added this .JAR and this one jackson-annotations-2.6.1.jar the class not found exception was solved. But I still have the original error 10-16 04:44:37.524: E/AndroidRuntime(1349): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1] that made me ask this question.

This are the changes that I did and when I think is the problem

// Populate the HTTP Basic Authentitcation header with the username
        // and password
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setAuthorization(authHeader);
        requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

        // Set OBJECT to send
        Person personToSend = new Person();
        personToSend.setId(23);
        personToSend.setName("Prueba");

        HttpEntity<Person> entityPerson = new HttpEntity<Person>(personToSend, requestHeaders);

        try {
            String json = "";

            JSONObject jsonObject = new JSONObject();

            jsonObject.accumulate("id", "2");
            jsonObject.accumulate("name", "hola");
            json = jsonObject.toString();

            // Make the network request
            Log.d(TAG, url);

            ResponseEntity<Person> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<Object>(requestHeaders), Person.class);
            return response.getBody();

I tried to use MappingJackson2HttpMessageConverter as my converter as is suggested here in this similar questions:

Force Spring RestTemplate to use XmlConverter and Could not extract response: no suitable HttpMessageConverter found for response type, but still I get the same error

but still I get the same error `10-16 04:44:37.524: E/AndroidRuntime(1349): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1]

EDIT 2:

I changed my controller annotations and added the produces = "application/json" into the RequestMappin method like this

@RequestMapping(value = "changeNameAfter", method = RequestMethod.POST, produces = "application/json")
    public @ResponseBody
    Person methodChangeStringPro(@RequestBody final String json, Model model)
            throws IOException {

But still it gives me the same error.

E/AndroidRuntime(1349): Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [modelo.Person] and content type [text/html;charset=ISO-8859-1]
StackQuestion
  • 483
  • 2
  • 7
  • 20
  • Have a look at http://stackoverflow.com/questions/13038529/force-spring-resttemplate-to-use-xmlconverter and http://stackoverflow.com/questions/24723394/could-not-extract-response-no-suitable-httpmessageconverter-found-for-response. I suspect the issue with Content-Type setting in headers – Ravindra babu Oct 16 '15 at 02:43
  • the first link they were using XML and not JSON, in the second link they recomended to use MappingJackson2HttpMessageConverter so I added the following library "jackson-databind-2.6.1.jar" to my libs folder but now when I have a class not found error 10-16 03:12:53.961: E/AndroidRuntime(1324): Caused by: java.lang.NoClassDefFoundError: com.fasterxml.jackson.databind.ObjectMapper 10-16 03:12:53.961: E/AndroidRuntime(1324): at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.(MappingJackson2HttpMessageConverter.java:55) – StackQuestion Oct 16 '15 at 03:29
  • Did you add databind-2.6.1.jar to java run time too? Form the error, it seems that jar is not in classpath – Ravindra babu Oct 16 '15 at 03:33
  • I import the library to my libs folder and then I clicked the jar and choose add to build path, I'm using eclipse – StackQuestion Oct 16 '15 at 03:52
  • You did not set the headers as explained in other two SE questions regarding content-type – Ravindra babu Oct 16 '15 at 05:14
  • @ravindra can you make an answer or give and example about how to set the headers, I think they are seted when I do this requestHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); also can this error mean that I have a bad security config somewhere and the text/html that is returng is a html page saying 404 or access denied or something similar? I think that my security config looks good – StackQuestion Oct 18 '15 at 04:10
  • I will try from my end in couple of days – Ravindra babu Oct 18 '15 at 07:51

0 Answers0