35

I've been struggling for a few days now. I'm kind of new in Spring Boot, and like the idea of not using XML configuration.

I created a RESTfull application (with JSON). I'm following this tutorial to configure authentication properly.

I think I managed to reproduce almost all of its configurations using Java configuration, except for one thing - AuthenticationEntryPoint

The tutorial uses a property in http tag like this and defines a formLogin in the following way:

<http entry-point-ref="restAuthenticationEntryPoint">

  <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN"/>

  <form-login
     authentication-success-handler-ref="mySuccessHandler"
     authentication-failure-handler-ref="myFailureHandler"
  />

  <logout />

</http>

The AuthenticationEntryPoint explanation in the Spring Security manual says:

AuthenticationEntryPoint can be set using the entry-point-ref attribute on the < http > element.

Doesn't mention anything about how to do it using Java Configuration.

So how can I "register" my own restAuthenticationEntryPoint without XML in order to prevent the redirection to a login form when using formLogin?

Below I will mention what I have tried.

Thank you all.


In my attempts, found you can define it using basicAuth like this:

@Configuration
@Order(1)                                                        
public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        if (restAuthenticationEntryPoint == null) {
            restAuthenticationEntryPoint = new RestAuthenticationEntryPoint();
        }

        http
            .authorizeRequests()
                .antMatchers("/**").hasAnyRole(Sec.ADMIN,Sec.SUPER_USER)
...
        .and()
            .httpBasic()
                .authenticationEntryPoint(restAuthenticationEntryPoint)

But I'm using a form login like this (without the httpBasic part):

        .and()
            .formLogin()
                .successHandler(mySavedRequestAwareAuthenticationSuccessHandler)
                .failureHandler(simpleUrlAuthenticationFailureHandler)

The problem is it redirects to a login form when it doesn't receive credentials. Since this is a REST service it shouldn't.

The documentation for FormLoginConfigurer (the class .formLogin() uses) says:

Shared Objects Created

The following shared objects are populated

AuthenticationEntryPoint

But couldn't find a way to override it.
Any ideas?

P.S.
Don't think it would be a good idea to override the login form to a custom one that only returns the error.

informatik01
  • 16,038
  • 10
  • 74
  • 104
elysch
  • 1,846
  • 4
  • 25
  • 43
  • Why do you have form login for a REST resource? Normally a form means you have a GUI (hence the redirect to a view page). Maybe HTTP Basic is all you need anyway? – Dave Syer Jul 10 '14 at 21:15
  • Thank's for your answer. I need formLogin in order to have a cookie instead of sending the credentials on every request. The front end is JavaScript (in fact angularJS), I don't like the idea of storing the username and password in the client – elysch Jul 10 '14 at 21:18
  • I see. You get a cookie for any authentication, so that isn't necessarily a good reason. Also, the browser will probably handle basic auth for you (I assume). – Dave Syer Jul 11 '14 at 05:41
  • As far as I could see, if I create a login page and use basic auth to "talk" to the rest service, the browser didn't "handle" it. I had to pass the credentials everywhere. Maybe I did something wrong. – elysch Jul 11 '14 at 11:28
  • Check the HTTP traffic. If you get a cookie from the login page then the browser should be sending it with every subsequent request. – Dave Syer Jul 11 '14 at 12:32
  • Good idea. I'll try it when I have some time. – elysch Jul 11 '14 at 12:55
  • Some added benefits of the formLogin are: a) Now I receive a nice message when the user is blocked or just entered wrong credentials. b) Even if my app accepts also basicAuth, it no longer shows the browser's login window when my javaScript login form fails. (someting I did already found a way to avoid, but still) – elysch Jul 11 '14 at 12:58

1 Answers1

65

The quote from the ref docs you provided is pointing you at http.exceptionHandling(). You can set up the shared entry point there.

http.exceptionHandling().authenticationEntryPoint(myEntryPoint);
Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • This works. Thank you so much. By the way. I couldn't find where the tutorial talks about exceptionHandling but a parameter in RestAuthenticationEntryPoint's commence method. How did you notice that? – elysch Jul 11 '14 at 12:50
  • I meant: Where did you find that reference to exceptionHandling in the tutorial that lead you to the answer. But in fact it was only a "wow" remark. :) – elysch Jul 11 '14 at 13:06
  • 2
    I didn't follow a tutorial. It's the same as the XML when you get to know the API, so I guessed, but I bet you can find it in the Security ref docs. – Dave Syer Jul 11 '14 at 13:12
  • 2
    Seems that Spring Security Reference doesn't have a single mention of the exceptionHandling() method, leaving the user to his own devices in figuring this out. – Samuli Pahaoja Aug 08 '14 at 06:01
  • 2
    It doesn't seem to appear directly in the reference, but you can find several examples in Spring documentation: [Example 1](https://spring.io/guides/tutorials/spring-boot-oauth2) [Example 2](http://docs.spring.io/spring-security-kerberos/docs/current/reference/htmlsingle/#ssk-spnego) – Aníbal Feb 13 '17 at 22:18