SEBSERV-4 #Unauthorized request redirect to login or respond with error
This commit is contained in:
parent
5a8ad16325
commit
b0b5876981
3 changed files with 89 additions and 36 deletions
|
@ -8,16 +8,29 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
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.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
|
||||
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
|
||||
|
@ -25,19 +38,37 @@ import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConv
|
|||
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebClientDetailsService;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebResourceServerConfiguration;
|
||||
|
||||
/** This is the main web-security Spring configuration for SEB-Server webservice API */
|
||||
/** This is the main web-security Spring configuration for SEB-Server webservice API
|
||||
*
|
||||
* Currently two separated Rest API's are implemented, one for administration and maintenance
|
||||
* of the SEB-Server (AdminAPI) and one for SEB-Client connection on running exams and eventually
|
||||
* also for LMS communication), if needed (ExamAPI). The AdministrationAPI uses OAuth 2 password
|
||||
* grant with refresh-token, same as in the prototype and the ExamAPI uses the client_credential grant.
|
||||
*
|
||||
* There is a Spring Authorization-Server defining this two clients (AdminAPIClient and ExamAPIClient) as well as
|
||||
* two Spring Resource-Server for the separation of the different API's
|
||||
*
|
||||
* The endpoint of the AdministrationAPI can be configured within the key; sebserver.webservice.api.admin.endpoint
|
||||
* and is by default set to "/admin-api/**"
|
||||
*
|
||||
* The endpoint of the ExamAPI can be configured within the key; sebserver.webservice.api.exam.endpoint
|
||||
* and is by default set to "/exam-api/**" */
|
||||
@WebServiceProfile
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableWebSecurity
|
||||
@Order(4)
|
||||
public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ClientSessionWebSecurityConfig.class);
|
||||
|
||||
/** Spring bean name of single AuthenticationManager bean */
|
||||
public static final String AUTHENTICATION_MANAGER = "AUTHENTICATION_MANAGER";
|
||||
|
||||
|
@ -103,6 +134,28 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
this.examAPIEndpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final HttpSecurity http) throws Exception {
|
||||
http
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.antMatcher("/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(new LoginRedirectOnUnauthorized())
|
||||
.and()
|
||||
.formLogin().disable()
|
||||
.httpBasic().disable()
|
||||
.logout().disable()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
}
|
||||
|
||||
// NOTE: We need two different class types here to support Spring configuration for different
|
||||
// ResourceServerConfiguration. There is a class type now for the Admin API as well as for the Exam API
|
||||
private static final class AdminAPIResourceServerConfiguration extends WebResourceServerConfiguration {
|
||||
|
@ -117,6 +170,7 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
tokenStore,
|
||||
webServiceClientDetails,
|
||||
authenticationManager,
|
||||
new LoginRedirectOnUnauthorized(),
|
||||
ADMIN_API_RESOURCE_ID,
|
||||
apiEndpoint,
|
||||
true,
|
||||
|
@ -138,6 +192,13 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
tokenStore,
|
||||
webServiceClientDetails,
|
||||
authenticationManager,
|
||||
(request, response, exception) -> {
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
log.warn("Unauthorized Request: {}", request, exception);
|
||||
log.info("Redirect to login after unauthorized request");
|
||||
response.getOutputStream().println("{ \"error\": \"" + exception.getMessage() + "\" }");
|
||||
},
|
||||
EXAM_API_RESOURCE_ID,
|
||||
apiEndpoint,
|
||||
true,
|
||||
|
@ -145,4 +206,22 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
}
|
||||
}
|
||||
|
||||
private static class LoginRedirectOnUnauthorized implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(
|
||||
final HttpServletRequest request,
|
||||
final HttpServletResponse response,
|
||||
final AuthenticationException authenticationException) throws IOException, ServletException {
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
log.warn("Unauthorized Request: {}", request, authenticationException);
|
||||
log.info("Redirect to login after unauthorized request");
|
||||
|
||||
// TODO define login redirect
|
||||
response.sendRedirect("/gui/");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/** Implements a custom unauthorized authentication error end-point */
|
||||
@Component
|
||||
public class CustomAuthenticationError implements AuthenticationEntryPoint {
|
||||
|
||||
@Override
|
||||
public void commence(final HttpServletRequest request, final HttpServletResponse response,
|
||||
final AuthenticationException authenticationException) throws IOException, ServletException {
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");
|
||||
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R
|
|||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
/** Abstract Spring ResourceServerConfiguration to configure different resource services
|
||||
* for different API's. */
|
||||
|
@ -34,6 +35,7 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
final TokenStore tokenStore,
|
||||
final WebClientDetailsService webServiceClientDetails,
|
||||
final AuthenticationManager authenticationManager,
|
||||
final AuthenticationEntryPoint authenticationEntryPoint,
|
||||
final String resourceId,
|
||||
final String apiEndpoint,
|
||||
final boolean supportRefreshToken,
|
||||
|
@ -44,6 +46,7 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
tokenStore,
|
||||
webServiceClientDetails,
|
||||
authenticationManager,
|
||||
authenticationEntryPoint,
|
||||
resourceId,
|
||||
apiEndpoint,
|
||||
supportRefreshToken);
|
||||
|
@ -62,6 +65,7 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
private final TokenStore tokenStore;
|
||||
private final WebClientDetailsService webServiceClientDetails;
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final AuthenticationEntryPoint authenticationEntryPoint;
|
||||
private final String resourceId;
|
||||
private final String apiEndpoint;
|
||||
private final boolean supportRefreshToken;
|
||||
|
@ -70,6 +74,7 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
final TokenStore tokenStore,
|
||||
final WebClientDetailsService webServiceClientDetails,
|
||||
final AuthenticationManager authenticationManager,
|
||||
final AuthenticationEntryPoint authenticationEntryPoint,
|
||||
final String resourceId,
|
||||
final String apiEndpoint,
|
||||
final boolean supportRefreshToken) {
|
||||
|
@ -78,6 +83,7 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
this.tokenStore = tokenStore;
|
||||
this.webServiceClientDetails = webServiceClientDetails;
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||
this.resourceId = resourceId;
|
||||
this.apiEndpoint = apiEndpoint;
|
||||
this.supportRefreshToken = supportRefreshToken;
|
||||
|
@ -105,6 +111,9 @@ public abstract class WebResourceServerConfiguration extends ResourceServerConfi
|
|||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(this.authenticationEntryPoint)
|
||||
.and()
|
||||
.formLogin().disable()
|
||||
.httpBasic().disable()
|
||||
.logout().disable()
|
||||
|
|
Loading…
Reference in a new issue