Added OAuth2 AuthServer and two ResServer for admin and monitoring
SEBSERV-4
This commit is contained in:
parent
807cae3e51
commit
cfa4525c21
14 changed files with 681 additions and 96 deletions
|
@ -16,6 +16,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
|
||||
@Configuration
|
||||
@SpringBootApplication(exclude = {
|
||||
// OAuth2ResourceServerAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class,
|
||||
DataSourceAutoConfiguration.class
|
||||
})
|
||||
|
|
|
@ -10,10 +10,6 @@ package ch.ethz.seb.sebserver;
|
|||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
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.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
|
@ -25,21 +21,13 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
|||
@Configuration
|
||||
@WebServiceProfile
|
||||
@GuiProfile
|
||||
@EnableWebSecurity
|
||||
@Order(0)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class WebSecurityConfig {
|
||||
|
||||
/** Spring bean name of user password encoder */
|
||||
public static final String USER_PASSWORD_ENCODER_BEAN_NAME = "userPasswordEncoder";
|
||||
/** Spring bean name of client (application) password encoder */
|
||||
public static final String CLIENT_PASSWORD_ENCODER_BEAN_NAME = "clientPasswordEncoder";
|
||||
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
System.out.println("**************** Overall WebConfig: ");
|
||||
|
||||
}
|
||||
|
||||
/** Password encoder used for user passwords (stronger protection) */
|
||||
@Bean(USER_PASSWORD_ENCODER_BEAN_NAME)
|
||||
public PasswordEncoder userPasswordEncoder() {
|
||||
|
|
34
src/main/java/ch/ethz/seb/sebserver/gbl/JSONMapper.java
Normal file
34
src/main/java/ch/ethz/seb/sebserver/gbl/JSONMapper.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.gbl;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.joda.JodaModule;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
public class JSONMapper extends ObjectMapper {
|
||||
|
||||
private static final long serialVersionUID = 2883304481547670626L;
|
||||
|
||||
public JSONMapper() {
|
||||
super();
|
||||
super.registerModule(new JodaModule());
|
||||
super.configure(
|
||||
com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
|
||||
false);
|
||||
super.configure(
|
||||
com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_WITH_ZONE_ID,
|
||||
false);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,97 +9,88 @@
|
|||
package ch.ethz.seb.sebserver.webservice.weblayer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
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.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
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;
|
||||
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
|
||||
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 ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.AdminResourceServerConfig;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.SebClientResourceServerConfig;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebServiceClientDetails;
|
||||
|
||||
/** Spring web security configuration for all endpoints needed for SEB-Client session management.
|
||||
* This are:
|
||||
*
|
||||
* <pre>
|
||||
* - /sebauth/sebhandshake/ the SEB-Client handshake and authentication endpoint
|
||||
* - /sebauth/lmshandshake/ the LMS-Client handshake and authentication endpoint
|
||||
* - /ws/ the root of all web-socket endpoints on HTTP level
|
||||
* </pre>
|
||||
*
|
||||
* This configuration secures the above endpoints by using custom client authentication filter */
|
||||
@Configuration
|
||||
@WebServiceProfile
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Order(2)
|
||||
@EnableWebSecurity
|
||||
public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
public static final AntPathRequestMatcher SEB_HANDSHAKE_ENDPOINT =
|
||||
new AntPathRequestMatcher("/sebauth/sebhandshake/**");
|
||||
public static final AntPathRequestMatcher SEB_WEB_SOCKET_ENDPOINT =
|
||||
new AntPathRequestMatcher("/ws/**");
|
||||
public static final AntPathRequestMatcher LMS_HANDSHAKE_ENDPOINT =
|
||||
new AntPathRequestMatcher("/sebauth/lmshandshake/**");
|
||||
|
||||
public static final RequestMatcher SEB_CLIENT_ENDPOINTS = new OrRequestMatcher(
|
||||
SEB_HANDSHAKE_ENDPOINT,
|
||||
SEB_WEB_SOCKET_ENDPOINT);
|
||||
|
||||
public static final RequestMatcher SEB_CONNECTION_PROTECTED_URLS = new OrRequestMatcher(
|
||||
SEB_CLIENT_ENDPOINTS,
|
||||
LMS_HANDSHAKE_ENDPOINT);
|
||||
/** Spring bean name of user password encoder */
|
||||
public static final String AUTHENTICATION_MANAGER = "AUTHENTICATION_MANAGER";
|
||||
|
||||
@Autowired
|
||||
private CustomAuthenticationError customAuthenticationError;
|
||||
private WebServiceUserDetails webServiceUserDetails;
|
||||
@Autowired
|
||||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME)
|
||||
private PasswordEncoder userPasswordEncoder;
|
||||
@Autowired
|
||||
private TokenStore tokenStore;
|
||||
@Autowired
|
||||
private WebServiceClientDetails webServiceClientDetails;
|
||||
|
||||
@Bean
|
||||
public AccessTokenConverter accessTokenConverter() {
|
||||
final DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
|
||||
accessTokenConverter.setUserTokenConverter(userAuthenticationConverter());
|
||||
return accessTokenConverter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserAuthenticationConverter userAuthenticationConverter() {
|
||||
final DefaultUserAuthenticationConverter userAuthenticationConverter =
|
||||
new DefaultUserAuthenticationConverter();
|
||||
userAuthenticationConverter.setUserDetailsService(this.webServiceUserDetails);
|
||||
return userAuthenticationConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
System.out.println("**************** WebServiceWebConfig: ");
|
||||
//@formatter:off
|
||||
http
|
||||
// The Web-Service is designed as a stateless Rest API
|
||||
// for SEB session management only endpoints for handshake and web-socket is used what is stateless on HTTP
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
|
||||
// TODO
|
||||
// .and()
|
||||
// .requestMatcher(SEB_CONNECTION_PROTECTED_URLS)
|
||||
// .addFilterBefore(
|
||||
// this.sebClientAuthenticationFilter,
|
||||
// BasicAuthenticationFilter.class)
|
||||
// .addFilterBefore(
|
||||
// this.lmsClientAuthenticationFilter,
|
||||
// SEBClientAuthenticationFilter.class)
|
||||
// .authorizeRequests()
|
||||
// .requestMatchers(SEB_CONNECTION_PROTECTED_URLS)
|
||||
// .authenticated()
|
||||
// instead of:
|
||||
|
||||
.and()
|
||||
.antMatcher("/webservice/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.fullyAuthenticated()
|
||||
// end TODO
|
||||
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
.defaultAuthenticationEntryPointFor(
|
||||
this.customAuthenticationError,
|
||||
SEB_CONNECTION_PROTECTED_URLS)
|
||||
|
||||
.and()
|
||||
// disable session based security and functionality
|
||||
.formLogin().disable()
|
||||
.httpBasic().disable()
|
||||
.logout().disable()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
//@formatter:on
|
||||
@Bean(AUTHENTICATION_MANAGER)
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
final AuthenticationManager authenticationManagerBean = super.authenticationManagerBean();
|
||||
return authenticationManagerBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.userDetailsService(this.webServiceUserDetails)
|
||||
.passwordEncoder(this.userPasswordEncoder);
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected ResourceServerConfiguration sebServerAdminAPIResources() {
|
||||
return new AdminResourceServerConfig(accessTokenConverter());
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected ResourceServerConfiguration sebServerSebClientAPIResources() throws Exception {
|
||||
return new SebClientResourceServerConfig(
|
||||
accessTokenConverter(),
|
||||
this.tokenStore,
|
||||
this.webServiceClientDetails,
|
||||
authenticationManagerBean());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.security.Principal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/sebclient")
|
||||
@WebServiceProfile
|
||||
public class SebClientTestController {
|
||||
|
||||
@RequestMapping(value = "/hello", method = RequestMethod.GET)
|
||||
public String helloFromWebService(final Principal principal) {
|
||||
return "Hello From Seb-Cleint-Web-Service";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.util.Collections;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
public class WebServiceUserDetails implements UserDetailsService {
|
||||
|
||||
// private final UserDao userDao;
|
||||
//
|
||||
// public InternalUserDetailsService(final UserDao userDao) {
|
||||
// this.userDao = userDao;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
|
||||
return new User(
|
||||
username,
|
||||
"$2a$04$btj5PkII8IIHLE7zbQOd3u7YghHeClG7k1ZzYbtybRnd5h1YqwTf.",
|
||||
Collections.emptyList());
|
||||
|
||||
// try {
|
||||
// final org.eth.demo.sebserver.domain.rest.admin.User byUserName = this.userDao.byUserName(username);
|
||||
// if (byUserName == null) {
|
||||
// throw new UsernameNotFoundException("No User with name: " + username + " found");
|
||||
// }
|
||||
// return byUserName;
|
||||
// } catch (final Exception e) {
|
||||
// throw new UsernameNotFoundException("No User with name: " + username + " found");
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
@ -15,7 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/webservice")
|
||||
@RequestMapping("/admin")
|
||||
@WebServiceProfile
|
||||
public class WsTestController {
|
||||
|
||||
|
@ -23,9 +25,9 @@ public class WsTestController {
|
|||
System.out.println("************** TestController webservice");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
||||
public String helloFromWebService() {
|
||||
return "Hello From Web-Service";
|
||||
@RequestMapping(value = "/hello", method = RequestMethod.GET)
|
||||
public String helloFromWebService(final Principal principal) {
|
||||
return "Hello From Admin-Web-Service";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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.oauth;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
|
||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
public class AdminResourceServerConfig extends ResourceServerConfiguration {
|
||||
|
||||
@Value("${server.address}")
|
||||
private String webServerAdress;
|
||||
@Value("${server.port}")
|
||||
private String webServerPort;
|
||||
@Value("${sebserver.webservice.protocol}")
|
||||
private String webProtocol;
|
||||
@Value("${sebserver.oauth.clients.guiClient.id}")
|
||||
private String guiClientId;
|
||||
// TODO secret should not be referenced here (should go to stack and disappear after use)
|
||||
@Value("${sebserver.oauth.clients.guiClient.secret}")
|
||||
private String guiClientSecret;
|
||||
|
||||
public AdminResourceServerConfig(final AccessTokenConverter accessTokenConverter) {
|
||||
setConfigurers(Arrays.<ResourceServerConfigurer> asList(new ResourceServerConfigurerAdapter() {
|
||||
|
||||
@Override
|
||||
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
|
||||
resources.resourceId(GuiClientDetails.RESOURCE_ID);
|
||||
// TODO try to use DefualtTokenServices like in SebClientResourceServerConfig
|
||||
final RemoteTokenServices tokenService = new RemoteTokenServices();
|
||||
tokenService.setCheckTokenEndpointUrl(
|
||||
UriComponentsBuilder
|
||||
.fromHttpUrl(AdminResourceServerConfig.this.webProtocol + "://"
|
||||
+ AdminResourceServerConfig.this.webServerAdress)
|
||||
.port(AdminResourceServerConfig.this.webServerPort)
|
||||
.path("oauth/check_token")
|
||||
.toUriString());
|
||||
tokenService.setClientId(AdminResourceServerConfig.this.guiClientId);
|
||||
tokenService.setClientSecret(AdminResourceServerConfig.this.guiClientSecret);
|
||||
tokenService.setAccessTokenConverter(accessTokenConverter);
|
||||
resources.tokenServices(tokenService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final HttpSecurity http) throws Exception {
|
||||
http
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.antMatcher("/admin/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.formLogin().disable()
|
||||
.httpBasic().disable()
|
||||
.logout().disable()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
}
|
||||
|
||||
}));
|
||||
setOrder(1);
|
||||
}
|
||||
|
||||
// Switch off the Spring Boot auto configuration
|
||||
@Override
|
||||
public void setConfigurers(final List<ResourceServerConfigurer> configurers) {
|
||||
super.setConfigurers(configurers);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.oauth;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
|
||||
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.ClientSessionWebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.WebServiceUserDetails;
|
||||
|
||||
@WebServiceProfile
|
||||
@Configuration
|
||||
@EnableAuthorizationServer
|
||||
@Order(100)
|
||||
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private AccessTokenConverter accessTokenConverter;
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@Autowired
|
||||
private WebServiceUserDetails webServiceUserDetails;
|
||||
@Autowired
|
||||
private WebServiceClientDetails webServiceClientDetails;
|
||||
@Autowired
|
||||
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME)
|
||||
private PasswordEncoder clientPasswordEncoder;
|
||||
@Autowired
|
||||
@Qualifier(ClientSessionWebSecurityConfig.AUTHENTICATION_MANAGER)
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Override
|
||||
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
|
||||
oauthServer
|
||||
.tokenKeyAccess("permitAll()")
|
||||
.checkTokenAccess("isAuthenticated()")
|
||||
.passwordEncoder(this.clientPasswordEncoder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
|
||||
clients.withClientDetails(this.webServiceClientDetails);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenStore tokenStore() {
|
||||
return new JdbcTokenStore(this.dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
|
||||
final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
|
||||
jwtAccessTokenConverter.setAccessTokenConverter(this.accessTokenConverter);
|
||||
endpoints
|
||||
.tokenStore(tokenStore())
|
||||
.authenticationManager(this.authenticationManager)
|
||||
.userDetailsService(this.webServiceUserDetails)
|
||||
.accessTokenConverter(jwtAccessTokenConverter);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* 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.oauth;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.Lazy;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
public final class GuiClientDetails implements ClientDetails {
|
||||
|
||||
private static final long serialVersionUID = 4505193832353978832L;
|
||||
|
||||
public static final String RESOURCE_ID = "seb-server-administration-api";
|
||||
|
||||
private static final Set<String> GRANT_TYPES = Utils.immutableSetOf("password", "refresh_token");
|
||||
private static final Set<String> RESOURCE_IDS = Utils.immutableSetOf(RESOURCE_ID);
|
||||
private static final Set<String> SCOPES = Utils.immutableSetOf("read", "write");
|
||||
|
||||
private final String guiClientId;
|
||||
private final String guiClientSecret;
|
||||
private final Integer guiClientAccessTokenValiditySeconds;
|
||||
private final Integer guiClientRefreshTokenValiditySeconds;
|
||||
|
||||
public GuiClientDetails(
|
||||
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder clientPasswordEncoder,
|
||||
@Value("${sebserver.oauth.clients.guiClient.id}") final String guiClientId,
|
||||
@Value("${sebserver.oauth.clients.guiClient.secret}") final String guiClientSecret,
|
||||
@Value("${sebserver.oauth.clients.guiClient.accessTokenValiditySeconds}") final Integer guiClientAccessTokenValiditySeconds,
|
||||
@Value("${sebserver.oauth.clients.guiClient.refreshTokenValiditySeconds}") final Integer guiClientRefreshTokenValiditySeconds) {
|
||||
|
||||
this.guiClientId = guiClientId;
|
||||
this.guiClientSecret = clientPasswordEncoder.encode(guiClientSecret);
|
||||
this.guiClientAccessTokenValiditySeconds = guiClientAccessTokenValiditySeconds;
|
||||
this.guiClientRefreshTokenValiditySeconds = guiClientRefreshTokenValiditySeconds;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME)
|
||||
private PasswordEncoder clientPasswordEncoder;
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return this.guiClientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceIds() {
|
||||
return RESOURCE_IDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecretRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientSecret() {
|
||||
return this.guiClientSecret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScoped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getScope() {
|
||||
return SCOPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAuthorizedGrantTypes() {
|
||||
return GRANT_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRegisteredRedirectUri() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getAccessTokenValiditySeconds() {
|
||||
return this.guiClientAccessTokenValiditySeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getRefreshTokenValiditySeconds() {
|
||||
return this.guiClientRefreshTokenValiditySeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoApprove(final String scope) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.guiClientId == null) ? 0 : this.guiClientId.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final GuiClientDetails other = (GuiClientDetails) obj;
|
||||
if (this.guiClientId == null) {
|
||||
if (other.guiClientId != null)
|
||||
return false;
|
||||
} else if (!this.guiClientId.equals(other.guiClientId))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GuiClientDetails [guiClientId=" + this.guiClientId + ", guiClientSecret=" + this.guiClientSecret
|
||||
+ ", guiClientAccessTokenValiditySeconds=" + this.guiClientAccessTokenValiditySeconds
|
||||
+ ", guiClientRefreshTokenValiditySeconds=" + this.guiClientRefreshTokenValiditySeconds
|
||||
+ ", clientPasswordEncoder=" + this.clientPasswordEncoder + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.oauth;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
||||
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
|
||||
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
|
||||
public class SebClientResourceServerConfig extends ResourceServerConfiguration {
|
||||
|
||||
public SebClientResourceServerConfig(
|
||||
final AccessTokenConverter accessTokenConverter,
|
||||
final TokenStore tokenStore,
|
||||
final WebServiceClientDetails webServiceClientDetails,
|
||||
final AuthenticationManager authenticationManager) {
|
||||
|
||||
setConfigurers(Arrays.<ResourceServerConfigurer> asList(new ResourceServerConfigurerAdapter() {
|
||||
|
||||
@Override
|
||||
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
|
||||
resources.resourceId(WebServiceClientDetails.RESOURCE_ID);
|
||||
final DefaultTokenServices tokenService = new DefaultTokenServices();
|
||||
tokenService.setTokenStore(tokenStore);
|
||||
tokenService.setClientDetailsService(webServiceClientDetails);
|
||||
tokenService.setSupportRefreshToken(false);
|
||||
tokenService.setAuthenticationManager(authenticationManager);
|
||||
resources.tokenServices(tokenService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final HttpSecurity http) throws Exception {
|
||||
http
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
.antMatcher("/sebclient/**")
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.formLogin().disable()
|
||||
.httpBasic().disable()
|
||||
.logout().disable()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.csrf().disable();
|
||||
}
|
||||
|
||||
}));
|
||||
setOrder(2);
|
||||
}
|
||||
|
||||
// Switch off the Spring Boot auto configuration
|
||||
@Override
|
||||
public void setConfigurers(final List<ResourceServerConfigurer> configurers) {
|
||||
super.setConfigurers(configurers);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.oauth;
|
||||
|
||||
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.Lazy;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||
import org.springframework.security.oauth2.provider.ClientRegistrationException;
|
||||
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
public class WebServiceClientDetails implements ClientDetailsService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WebServiceClientDetails.class);
|
||||
|
||||
public static final String[] SEB_CLIENT_GRANT_TYPES = new String[] { "client_credentials", "refresh_token" };
|
||||
public static final String[] SEB_CLIENT_SCOPES = new String[] { "web-service-api-read", "web-service-api-write" };
|
||||
public static final String RESOURCE_ID = "seb-server-seb-client-api";
|
||||
|
||||
@Value("${sebserver.oauth.clients.guiClient.accessTokenValiditySeconds}")
|
||||
private Integer guiClientAccessTokenValiditySeconds;
|
||||
@Value("${sebserver.oauth.clients.guiClient.refreshTokenValiditySeconds}")
|
||||
private Integer guiClientRefreshTokenValiditySeconds;
|
||||
|
||||
private final GuiClientDetails guiClientDetails;
|
||||
@Autowired
|
||||
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME)
|
||||
private PasswordEncoder clientPasswordEncoder;
|
||||
|
||||
public WebServiceClientDetails(final GuiClientDetails guiClientDetails) {
|
||||
this.guiClientDetails = guiClientDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientDetails loadClientByClientId(final String clientId) throws ClientRegistrationException {
|
||||
if (clientId == null) {
|
||||
throw new ClientRegistrationException("clientId is null");
|
||||
}
|
||||
|
||||
if (clientId.equals(this.guiClientDetails.getClientId())) {
|
||||
return this.guiClientDetails;
|
||||
}
|
||||
|
||||
final ClientDetails forSEBClientAPI = getForSEBClientAPI(clientId);
|
||||
if (forSEBClientAPI != null) {
|
||||
return forSEBClientAPI;
|
||||
}
|
||||
|
||||
log.warn("ClientDetails for clientId: {} not found", clientId);
|
||||
throw new ClientRegistrationException("clientId not found");
|
||||
}
|
||||
|
||||
private ClientDetails getForSEBClientAPI(final String clientId) {
|
||||
// TODO create ClientDetails from matching LMSSetup
|
||||
final BaseClientDetails baseClientDetails = new BaseClientDetails(
|
||||
clientId,
|
||||
RESOURCE_ID,
|
||||
"read,write",
|
||||
"client_credentials,refresh_token", "");
|
||||
baseClientDetails.setClientSecret(this.clientPasswordEncoder.encode("test"));
|
||||
return baseClientDetails;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
server.address=localhost
|
||||
server.port=8090
|
||||
server.servlet.context-path=/api/
|
||||
server.servlet.context-path=/
|
||||
|
||||
spring.datasource.initialize=true
|
||||
spring.datasource.initialization-mode=always
|
||||
|
@ -10,6 +10,8 @@ spring.datasource.platform=dev
|
|||
|
||||
sebserver.oauth.clients.guiClient.accessTokenValiditySeconds=1800
|
||||
sebserver.oauth.clients.guiClient.refreshTokenValiditySeconds=-1
|
||||
sebserver.oauth.clients.sebClient.accessTokenValiditySeconds=1800
|
||||
sebserver.oauth.clients.sebClient.refreshTokenValiditySeconds=-1
|
||||
|
||||
sebserver.webservice.protocol=http
|
||||
sebserver.client.connection-strategy=HTTP
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<Logger name="org.springframework.messaging" level="INFO" additivity="true" />
|
||||
|
||||
<Logger name="org.springframework.web" level="DEBUG" additivity="true" />
|
||||
<Logger name="org.springframework.security.oauth2" level="DEBUG" additivity="true" />
|
||||
|
||||
<root level="INFO" additivity="true">
|
||||
<appender-ref ref="STDOUT" />
|
||||
|
|
Loading…
Reference in a new issue