diff --git a/auth-service/pom.xml b/auth-service/pom.xml
index 08c8295..31d368c 100644
--- a/auth-service/pom.xml
+++ b/auth-service/pom.xml
@@ -73,7 +73,7 @@
com.h2database
h2
- runtime
+
org.springframework.boot
@@ -91,6 +91,11 @@
springloaded
1.2.6.RELEASE
+
+ org.springframework.integration
+ spring-integration-core
+ 4.3.5.RELEASE
+
diff --git a/auth-service/src/main/java/com/jservlet/AuthServiceApplication.java b/auth-service/src/main/java/com/jservlet/AuthServiceApplication.java
index b76f26d..df01dc2 100644
--- a/auth-service/src/main/java/com/jservlet/AuthServiceApplication.java
+++ b/auth-service/src/main/java/com/jservlet/AuthServiceApplication.java
@@ -2,19 +2,22 @@
import org.apache.log4j.Logger;
import org.hibernate.validator.constraints.NotEmpty;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.*;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.*;
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;
@@ -26,18 +29,36 @@
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
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.configuration.EnableResourceServer;
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.ClientDetailsService;
-import org.springframework.security.oauth2.provider.ClientRegistrationException;
+import org.springframework.security.oauth2.provider.*;
+import org.springframework.security.oauth2.provider.approval.ApprovalStore;
+import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
+import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
+import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
+import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
+import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
+import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
+import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
+import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
+import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
+import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+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 org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.persistence.*;
@@ -47,6 +68,7 @@
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
+import java.io.Serializable;
import java.security.Principal;
import java.util.*;
import java.util.stream.Collectors;
@@ -55,14 +77,9 @@
/**
* A Minimal Security OAuth2 Server
*
- * Active OAuth2 with Openid JWT (Jason Web Token) SHA256 with RSA private/public keys in config!
- *
- * curl http://localhost:9191/uaa/oauth/token_key
- * {"alg":"SHA256withRSA",
- * "value":"-----BEGIN PUBLIC KEY-----
- * MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNQZKqTlO/+2b4ZdhqGJzGBDltb5PZmBz1ALN2YLvt341pH6i5mO1V9cX5Ty1LM70fKfnIoYUP4KCE
- * 33dPnC7LkUwE/myh1zM6m8cbL5cYFPyP099thbVxzJkjHWqywvQih/qOOjliomKbM9pxG8Z1dB26hL9dSAZuA8xExjlPmQIDAQAB
- * -----END PUBLIC KEY-----"}
+ * curl -v -s --user acme:$2a$10$z/8fQRJlWmEB2jU3kC2rueX0gtVi340X2/bri6U5Yxw4tdHG/vZJS http://localhost:9191/uaa/oauth/token -d grant_type=password -d client_id=acme -d scope=read -d username=franck -d password=spring
+ * curl -v -s --user acme:$2a$10$z/8fQRJlWmEB2jU3kC2rueX0gtVi340X2/bri6U5Yxw4tdHG/vZJS http://localhost:9191/uaa/oauth/token -d grant_type=client_credentials -d scope=read
+ * curl -v -s --user acme:$2a$10$z/8fQRJlWmEB2jU3kC2rueX0gtVi340X2/bri6U5Yxw4tdHG/vZJS http://localhost:9191/uaa/oauth/token -d grant_type=authorization_code -d client_id=acme -d redirect_uri=http://example.com -d code=LCd7zR
*
* *************
* Code grant
@@ -110,6 +127,8 @@
*
* Use this TOKEN as a parameter of http request... access_token=9bf70492-6dad-40f4-9d6a-0237e5c1dec4
*
+ * See h2-console on Eureka Service http://localhost:8761/h2-console/
+ *
* @author Franck Andriano 2016
*/
@EnableDiscoveryClient
@@ -131,8 +150,8 @@ interface AuthoritiesRepository extends JpaRepository {
List findByUsername(String username);
}
-interface ClientRepository extends JpaRepository {
- Optional findByClientId(String clientId);
+interface ClientRepository extends JpaRepository {
+ Optional findByClientId(String clientId);
}
@Component
@@ -145,7 +164,8 @@ class OAuth2InitConfig implements CommandLineRunner {
private final ClientRepository clientRepository;
@Autowired
- public OAuth2InitConfig(UsersRepository usersRepository, AuthoritiesRepository authoritiesRepository,
+ public OAuth2InitConfig(UsersRepository usersRepository,
+ AuthoritiesRepository authoritiesRepository,
ClientRepository clientRepository) {
this.usersRepository = usersRepository;
this.authoritiesRepository = authoritiesRepository;
@@ -180,7 +200,7 @@ public void run(String... strings) throws Exception {
// Clients
if (clientRepository.findAll().isEmpty()) {
Stream.of("acme,acmesecret", "mobile,secret", "html5,secret").map(x -> x.split(","))
- .forEach(tpl -> clientRepository.save(new Client(tpl[0], new BCryptPasswordEncoder(10).encode(tpl[1]))));
+ .forEach(tpl -> clientRepository.save(new Clients(tpl[0], new BCryptPasswordEncoder(10).encode(tpl[1]))));
logger.warn("ClientRepository creation:");
}
else logger.warn("ClientRepository injection:");
@@ -198,7 +218,8 @@ class OAuth2ServerConfig {
private final UsersRepository usersRepository;
@Autowired
- public OAuth2ServerConfig(UsersRepository usersRepository, AuthoritiesRepository authoritiesRepository,
+ public OAuth2ServerConfig(UsersRepository usersRepository,
+ AuthoritiesRepository authoritiesRepository,
ClientRepository clientRepository) {
this.usersRepository = usersRepository;
this.authoritiesRepository = authoritiesRepository;
@@ -211,16 +232,16 @@ ClientDetailsService clientDetailsService() {
.map(client -> {
BaseClientDetails details = new BaseClientDetails(
client.getClientId(),
- null,
- client.getScopes(),
+ client.getResourceIds(),
+ client.getScope(),
client.getAuthorizedGrantTypes(),
client.getAuthorities(),
- client.getRegisteredRedirectUri()
+ client.getWebServerRedirectUri()
);
- details.setClientSecret(client.getSecret());
- details.setAutoApproveScopes(Arrays.asList(client.getAutoApproveScopes().split(",")));
- details.setAccessTokenValiditySeconds(1800); // 30mn Token < 1h RefreshToken!
- details.setRefreshTokenValiditySeconds(3600);
+ details.setClientSecret(client.getClientSecret());
+ details.setAutoApproveScopes(Arrays.asList(client.getAutoapprove().split(",")));
+ details.setAccessTokenValiditySeconds(client.getAccessTokenValidity()); // 30mn Token < 1h RefreshToken!
+ details.setRefreshTokenValiditySeconds(client.getRefreshTokenValidity());
return details;
})
.orElseThrow(() -> new ClientRegistrationException(String.format("no client %s registered", clientId)));
@@ -308,7 +329,7 @@ public void update(@RequestParam(value = "username") String username,
Optional optional = usersRepository.findByUsername(username);
Users user = optional.get();
user.setPassword(new BCryptPasswordEncoder(10).encode(password));
- usersRepository.saveAndFlush(user);
+ usersRepository.save(user);
logger.warn("UsersRepository update user: " + optional.get().getUsername());
}
} else response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
@@ -330,8 +351,7 @@ public void delete(@RequestParam(value = "username") String username,
@GetMapping("/raw")
public Object[] raw(HttpServletRequest request) { // Return a raw list!
- if (request.isUserInRole("ROLE_SUPERVISOR")) return usersRepository.findAll().toArray();
- else return null;
+ return request.isUserInRole("ROLE_SUPERVISOR") ? usersRepository.findAll().toArray() : null;
}
}
@@ -353,9 +373,11 @@ public WebSecurityConfig(UserDetailsService userDetailsService) {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/oauth/token", "/oauth/token_key").permitAll()
+ .requestMatchers().antMatchers(HttpMethod.OPTIONS, "/oauth/token")
.and()
- .csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ .csrf().disable().authorizeRequests().anyRequest().permitAll()
+ .and()
+ .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// @formatter:on
}
@@ -375,7 +397,7 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
- response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
+ response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
response.setHeader("Access-Control-Max-Age", "1800");
response.setHeader("Access-Control-Allow-Headers", "origin,accept,x-requested-with,content-type,access-control-request-method,access-control-request-headers,authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
@@ -398,33 +420,23 @@ class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private Logger logger = Logger.getLogger(getClass());
- @Value("${config.oauth2.private-key}")
- private String privateKey;
+ @Autowired
+ DataSource dataSource;
+
+ @Autowired
+ AuthorizationCodeServices authorizationCodeServices;
- @Value("${config.oauth2.public-key}")
- private String publicKey;
+ @Autowired
+ ApprovalStore approvalStore;
private final AuthenticationManager authenticationManager;
private final ClientDetailsService clientDetailsService;
private final UserDetailsService userDetailsService;
- @Bean
- public JwtAccessTokenConverter tokenEnhancer() {
- logger.warn("Initializing JWT with public key:\n" + publicKey);
- JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
- converter.setSigningKey(privateKey);
- converter.setVerifierKey(publicKey);
- return converter;
- }
-
- @Bean
- public JwtTokenStore tokenStore() { // Handle OAuth2 refresh JwtToken!
- return new JwtTokenStore(tokenEnhancer());
- }
-
@Autowired
public AuthorizationServerConfig(AuthenticationManager authenticationManager,
- ClientDetailsService clientDetailsService, UserDetailsService userDetailsService) {
+ ClientDetailsService clientDetailsService,
+ UserDetailsService userDetailsService) {
this.authenticationManager = authenticationManager;
this.clientDetailsService = clientDetailsService;
this.userDetailsService = userDetailsService;
@@ -437,21 +449,88 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
+
+ OAuth2RequestFactory oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
+
+ AuthorizationServerTokenServices tokenServices = tokenServices();
+
+ // Custom your TokenGranter!
+ ResourceOwnerPasswordTokenGranter resourceOwnerPasswordTokenGranter = new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices, clientDetailsService, oAuth2RequestFactory);
+ RefreshTokenGranter refreshTokenGranter = new RefreshTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory);
+ ImplicitTokenGranter implicitTokenGranter = new ImplicitTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory);
+ ClientCredentialsTokenGranter clientCredentialsTokenGranter = new ClientCredentialsTokenGranter(tokenServices, clientDetailsService, oAuth2RequestFactory);
+ AuthorizationCodeTokenGranter authorizationCodeTokenGranter = new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices(), clientDetailsService, oAuth2RequestFactory);
+
+ List tokenGranters = new ArrayList<>();
+ tokenGranters.add(resourceOwnerPasswordTokenGranter);
+ tokenGranters.add(refreshTokenGranter);
+ tokenGranters.add(implicitTokenGranter);
+ tokenGranters.add(clientCredentialsTokenGranter);
+ tokenGranters.add(authorizationCodeTokenGranter);
+
+ CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters);
+
// @formatter:off
endpoints
.tokenStore(tokenStore())
- .accessTokenConverter(tokenEnhancer())
- .authenticationManager(authenticationManager).userDetailsService(userDetailsService);
+ .tokenServices(tokenServices)
+ .approvalStore(approvalStore)
+ .requestFactory(oAuth2RequestFactory)
+ .authorizationCodeServices(authorizationCodeServices)
+ .tokenGranter(compositeTokenGranter)
+ .authenticationManager(authenticationManager)
+ .userDetailsService(userDetailsService)
+ .setClientDetailsService(clientDetailsService);
+
+ endpoints.exceptionTranslator(loggingExceptionTranslator());
// @formatter:on
}
- @Override
- public void configure(AuthorizationServerSecurityConfigurer server) throws Exception {
- server.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
- .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
+ @Bean
+ @Primary
+ public DefaultTokenServices tokenServices() {
+ DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
+ defaultTokenServices.setTokenStore(tokenStore());
+ defaultTokenServices.setSupportRefreshToken(true);
+ return defaultTokenServices;
+ }
+
+ @Bean
+ public TokenStore tokenStore() {
+ return new JdbcTokenStore(dataSource);
+ }
+
+ @Bean
+ protected AuthorizationCodeServices authorizationCodeServices() {
+ return new JdbcAuthorizationCodeServices(dataSource);
+ }
+
+ @Bean
+ protected ApprovalStore approvalStore() {
+ return new JdbcApprovalStore(dataSource);
+ }
+
+ @Bean
+ public WebResponseExceptionTranslator loggingExceptionTranslator() {
+ return new DefaultWebResponseExceptionTranslator() {
+ @Override
+ public ResponseEntity translate(Exception e) throws Exception {
+ // This is the line that prints the stack trace to the log.
+ // You can customise this to format the trace etc if you like
+ e.printStackTrace();
+
+ // Carry on handling the exception
+ ResponseEntity responseEntity = super.translate(e);
+ HttpHeaders headers = new HttpHeaders();
+ headers.setAll(responseEntity.getHeaders().toSingleValueMap());
+ OAuth2Exception excBody = responseEntity.getBody();
+ return new ResponseEntity<>(excBody, headers, responseEntity.getStatusCode());
+ }
+ };
}
}
+
// See bootstrap.properties h2 database server config!
// DROP TABLE IF EXISTS USERS;
// create table users(ID BIGINT auto_increment PRIMARY KEY, username varchar_ignorecase(50) not null unique, password varchar_ignorecase(255) not null, enabled boolean not null);
@@ -546,73 +625,130 @@ public String toString() {
}
}
-// Customized oauth_client_details table
-// DROP TABLE IF EXISTS CLIENT;
-// CREATE TABLE CLIENT(ID BIGINT auto_increment PRIMARY KEY,CLIENT_ID VARCHAR(255),SECRET VARCHAR(255),SCOPES VARCHAR(255),
-// AUTHORIZED_GRANT_TYPES VARCHAR(255),AUTHORITIES VARCHAR(255),AUTO_APPROVE_SCOPES VARCHAR(255), REGISTERED_REDIRECT_URI VARCHAR(1024));
+// See ../resources/schema.sql
@Entity
-class Client {
+@Table(name = "oauth_client_details")
+class Clients implements Serializable {
@Id
- @GeneratedValue
- private Long id;
-
- @NotEmpty
- private String clientId, secret;
- private String scopes = from("read", "write");
+ private String clientId;
+ private String clientSecret;
+ private String resourceIds = null;
+ private String scope = from("read", "write");
private String authorizedGrantTypes = from("client_credentials", "implicit", "authorization_code", "refresh_token", "password");
+ private String webServerRedirectUri = from("");
private String authorities = from("ROLE_USER", "ROLE_ADMIN");
- private String autoApproveScopes = from("true");
- private String registeredRedirectUri = from();
+ private Integer accessTokenValidity = 1800; // 30mn Token < 1h RefreshToken!
+ private Integer refreshTokenValidity = 3600;
+ private String additionalInformation = "SSO RestWeb";
+ private String autoapprove = from("true");
- public String getScopes() {
- return scopes;
+ Clients() { // JPA why !?
+ }
+
+ public Clients(String clientId, String clientSecret) {
+ this.clientId = clientId;
+ this.clientSecret = clientSecret;
+ }
+
+ private static String from(String... arr) {
+ return Arrays.stream(arr).collect(Collectors.joining(","));
+ }
+
+ public String getClientId() {
+ return this.clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientSecret() {
+ return this.clientSecret;
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ public String getResourceIds() {
+ return this.resourceIds;
+ }
+
+ public void setResourceIds(String resourceIds) {
+ this.resourceIds = resourceIds;
+ }
+
+ public String getScope() {
+ return this.scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
}
public String getAuthorizedGrantTypes() {
- return authorizedGrantTypes;
+ return this.authorizedGrantTypes;
+ }
+
+ public void setAuthorizedGrantTypes(String authorizedGrantTypes) {
+ this.authorizedGrantTypes = authorizedGrantTypes;
+ }
+
+ public String getWebServerRedirectUri() {
+ return this.webServerRedirectUri;
+ }
+
+ public void setWebServerRedirectUri(String webServerRedirectUri) {
+ this.webServerRedirectUri = webServerRedirectUri;
}
public String getAuthorities() {
- return authorities;
+ return this.authorities;
}
- public String getAutoApproveScopes() {
- return autoApproveScopes;
+ public void setAuthorities(String authorities) {
+ this.authorities = authorities;
}
- public String getRegisteredRedirectUri() {
- return registeredRedirectUri;
+ public Integer getAccessTokenValidity() {
+ return this.accessTokenValidity;
}
- private static String from(String... arr) {
- return Arrays.stream(arr).collect(Collectors.joining(","));
+ public void setAccessTokenValidity(Integer accessTokenValidity) {
+ this.accessTokenValidity = accessTokenValidity;
}
- public Client(String clientId, String clientSecret) {
- this.clientId = clientId;
- this.secret = clientSecret;
+ public Integer getRefreshTokenValidity() {
+ return this.refreshTokenValidity;
}
- Client() { // JPA why !?
+ public void setRefreshTokenValidity(Integer refreshTokenValidity) {
+ this.refreshTokenValidity = refreshTokenValidity;
}
- public Long getId() {
- return id;
+ public String getAdditionalInformation() {
+ return this.additionalInformation;
}
- public String getClientId() {
- return clientId;
+ public void setAdditionalInformation(String additionalInformation) {
+ this.additionalInformation = additionalInformation;
}
- public String getSecret() {
- return secret;
+ public String getAutoapprove() {
+ return this.autoapprove;
+ }
+
+ public void setAutoapprove(String autoapprove) {
+ this.autoapprove = autoapprove;
}
@Override
public String toString() {
- return "Client { clientId: " + clientId + ", secret: " + secret + ", scopes: [" + scopes +
+ return "Client { clientId: " + clientId + ", clientSecret: " + clientSecret + ", scope: [" + scope +
"], authorizedGrantTypes: [" + authorizedGrantTypes + "], authorities: [" + authorities +
- "] autoApproveScopes: [" + autoApproveScopes + "], registeredRedirectUri: [" + registeredRedirectUri + "] }";
+ "], accessTokenValidity: [" + accessTokenValidity + "], refreshTokenValidity: [" + refreshTokenValidity +
+ "] autoapprove: [" + autoapprove + "], webServerRedirectUri: [" + webServerRedirectUri + "] }";
}
-}
\ No newline at end of file
+
+}
diff --git a/auth-service/src/main/resources/bootstrap.properties b/auth-service/src/main/resources/bootstrap.properties
index 2e58c95..b09c30a 100644
--- a/auth-service/src/main/resources/bootstrap.properties
+++ b/auth-service/src/main/resources/bootstrap.properties
@@ -23,29 +23,12 @@ spring.jpa.show-sql=true
# openssl genrsa -out jwt.pem 2048
# openssl rsa -in jwt.pem
-config.oauth2.private-key=\
- -----BEGIN RSA PRIVATE KEY----- \
- MIICXQIBAAKBgQDNQZKqTlO/+2b4ZdhqGJzGBDltb5PZmBz1ALN2YLvt341pH6i5\
- mO1V9cX5Ty1LM70fKfnIoYUP4KCE33dPnC7LkUwE/myh1zM6m8cbL5cYFPyP099t\
- hbVxzJkjHWqywvQih/qOOjliomKbM9pxG8Z1dB26hL9dSAZuA8xExjlPmQIDAQAB\
- AoGAImnYGU3ApPOVtBf/TOqLfne+2SZX96eVU06myDY3zA4rO3DfbR7CzCLE6qPn\
- yDAIiW0UQBs0oBDdWOnOqz5YaePZu/yrLyj6KM6Q2e9ywRDtDh3ywrSfGpjdSvvo\
- aeL1WesBWsgWv1vFKKvES7ILFLUxKwyCRC2Lgh7aI9GGZfECQQD84m98Yrehhin3\
- fZuRaBNIu348Ci7ZFZmrvyxAIxrV4jBjpACW0RM2BvF5oYM2gOJqIfBOVjmPwUro\
- bYEFcHRvAkEAz8jsfmxsZVwh3Y/Y47BzhKIC5FLaads541jNjVWfrPirljyCy1n4\
- sg3WQH2IEyap3WTP84+csCtsfNfyK7fQdwJBAJNRyobY74cupJYkW5OK4OkXKQQL\
- Hp2iosJV/Y5jpQeC3JO/gARcSmfIBbbI66q9zKjtmpPYUXI4tc3PtUEY8QsCQQCc\
- xySyC0sKe6bNzyC+Q8AVvkxiTKWiI5idEr8duhJd589H72Zc2wkMB+a2CEGo+Y5H\
- jy5cvuph/pG/7Qw7sljnAkAy/feClt1mUEiAcWrHRwcQ71AoA0+21yC9VkqPNrn3\
- w7OEg8gBqPjRlXBNb00QieNeGGSkXOoU6gFschR22Dzy\
- -----END RSA PRIVATE KEY-----\
+#config.oauth2.private-key=\
+# -----BEGIN RSA PRIVATE KEY----- \
+# -----END RSA PRIVATE KEY-----\
# openssl rsa -in jwt.pem -pubout
-config.oauth2.public-key=\
- -----BEGIN PUBLIC KEY-----\
- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNQZKqTlO/+2b4ZdhqGJzGBDlt\
- b5PZmBz1ALN2YLvt341pH6i5mO1V9cX5Ty1LM70fKfnIoYUP4KCE33dPnC7LkUwE\
- /myh1zM6m8cbL5cYFPyP099thbVxzJkjHWqywvQih/qOOjliomKbM9pxG8Z1dB26\
- hL9dSAZuA8xExjlPmQIDAQAB\
- -----END PUBLIC KEY-----\
+#config.oauth2.public-key=\
+# -----BEGIN PUBLIC KEY-----\
+# -----END PUBLIC KEY-----\
diff --git a/auth-service/src/main/resources/schema.sql b/auth-service/src/main/resources/schema.sql
index 41b8b65..9a6c5f4 100644
--- a/auth-service/src/main/resources/schema.sql
+++ b/auth-service/src/main/resources/schema.sql
@@ -12,6 +12,66 @@ create table if not exists client(
registered_redirect_uri varchar(1024)
);
+-- drop table if exists oauth_client_details;
+create table if not exists oauth_client_details (
+ client_id VARCHAR(256) PRIMARY KEY,
+ resource_ids VARCHAR(256),
+ client_secret VARCHAR(256),
+ scope VARCHAR(256),
+ authorized_grant_types VARCHAR(256),
+ web_server_redirect_uri VARCHAR(256),
+ authorities VARCHAR(256),
+ access_token_validity INTEGER,
+ refresh_token_validity INTEGER,
+ additional_information VARCHAR(4096),
+ autoapprove VARCHAR(256)
+);
+
+-- INSERT INTO `oauth_client_details` (`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`)
+-- VALUES ('acme', '', '$2a$10$z/8fQRJlWmEB2jU3kC2rueX0gtVi340X2/bri6U5Yxw4tdHG/vZJS', 'read,write', 'refresh_token,password', NULL, 'ROLE_USER,ROLE_ADMIN', 0, 0, 'SSO', 'true');
+
+-- drop table if exists oauth_client_token;
+create table if not exists oauth_client_token (
+ token_id VARCHAR(256),
+ token LONGVARBINARY,
+ authentication_id VARCHAR(256) PRIMARY KEY,
+ user_name VARCHAR(256),
+ client_id VARCHAR(256)
+);
+
+-- drop table if exists oauth_access_token;
+create table if not exists oauth_access_token (
+ token_id VARCHAR(256),
+ token LONGVARBINARY,
+ authentication_id VARCHAR(256) PRIMARY KEY,
+ user_name VARCHAR(256),
+ client_id VARCHAR(256),
+ authentication LONGVARBINARY,
+ refresh_token VARCHAR(256)
+);
+
+-- drop table if exists oauth_refresh_token;
+create table if not exists oauth_refresh_token (
+ token_id VARCHAR(256),
+ token LONGVARBINARY,
+ authentication LONGVARBINARY
+);
+
+-- drop table if exists oauth_code;
+create table if not exists oauth_code (
+ code VARCHAR(256), authentication LONGVARBINARY
+);
+
+-- drop table if exists oauth_approvals;
+create table if not exists oauth_approvals (
+ userId VARCHAR(256),
+ clientId VARCHAR(256),
+ scope VARCHAR(256),
+ status VARCHAR(10),
+ expiresAt TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
+ lastModifiedAt TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'
+);
+
-- users table
-- drop table if exists users;
create table if not exists users(
@@ -29,4 +89,4 @@ create table if not exists authorities(
authority varchar_ignorecase(50) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
-create unique index if not exists ix_auth_username on authorities (username, authority);
\ No newline at end of file
+create unique index if not exists ix_auth_username on authorities (username, authority);
diff --git a/microservices-config/tcloud-client.properties b/microservices-config/tcloud-client.properties
index efafb01..480b12e 100644
--- a/microservices-config/tcloud-client.properties
+++ b/microservices-config/tcloud-client.properties
@@ -6,17 +6,26 @@ info.component=Tcloud Client with OAuth2 Sso
spring.cloud.stream.bindings.output.destination=tcloud
# Oauth2 Resource user endpoint
-#security.oauth2.resource.user-info-uri=http://localhost:9191/uaa/user
+security.oauth2.resource.user-info-uri=http://localhost:9191/uaa/user
# Oauth2 Resource jwt token endpoint
-security.oauth2.resource.jwt.key-uri=http://localhost:9191/uaa/oauth/token_key
+#security.oauth2.resource.jwt.key-uri=http://localhost:9191/uaa/oauth/token_key
+#security.oauth2.resource.id=tcloud
# Mandatory at false for OAuth2FeignConfig!
security.oauth2.resource.loadBalanced=false
# Active resource loadBalanced!
spring.oauth2.resource.loadBalanced=true
-#security.oauth2.resource.prefer-token-info=false
+
+
+# Oauth2 Resource Client
+#security.oauth2.client.client-id=acme
+#security.oauth2.client.client-secret=acmesecret
+#security.oauth2.client.access-token-uri=http://localhost:9191/uaa/oauth/token
+#security.oauth2.client.user-authorization-uri=http://localhost:9191/uaa/oauth/authorize
+#security.oauth2.client.client-authentication-scheme=header
+#security.oauth2.client.authentication-scheme=form
# Protect against CSRF attack! (Only path /login working, but forcing a HTTPS redirect URL!)
#security.oauth2.client.use-current-uri=false
diff --git a/tcloud-client/src/main/java/com/jservlet/TcloudClientApplication.java b/tcloud-client/src/main/java/com/jservlet/TcloudClientApplication.java
index dcaaaae..5ec1ecb 100644
--- a/tcloud-client/src/main/java/com/jservlet/TcloudClientApplication.java
+++ b/tcloud-client/src/main/java/com/jservlet/TcloudClientApplication.java
@@ -209,7 +209,7 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
- response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
+ response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
response.setHeader("Access-Control-Max-Age", "1800");
response.setHeader("Access-Control-Allow-Headers", "origin,accept,x-requested-with,content-type,access-control-request-method,access-control-request-headers,authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
@@ -277,7 +277,7 @@ public Docket tcloudApi() {
.securitySchemes(newArrayList(apiKey())) ;
}
- // Put Authorization bearer +' '+JWT (Jason Web Token)
+ // Put Authorization bearer +' '+Token
@Bean
SecurityScheme apiKey() {
return new ApiKey("Authorization", "api_key", "header");
@@ -287,7 +287,7 @@ private ApiInfo apiInfo() {
ApiInfo apiInfo = new ApiInfo(
"Tcloud API Manual",
"This online API manual for the development of client-side reference :\n" +
- "- Put Authorization header : Bearer+' '+JWT(Jason Web Token)\n",
+ "- Put Authorization header : Bearer+' '+Token\n",
"0.0.1", "Terms of service",
new Contact("Swagger Tcloud API Team", "https://github.com/javaguru/tcloud-microservices", "support@jservlet.com"),
"GPL-3.0 license", "https://github.com/javaguru/tcloud-microservices/blob/master/LICENSE");
@@ -303,7 +303,6 @@ class TcloudApiGateway {
private final TcloudReader tcloudReader;
-
/* private final TcloudWriter tcloudWriter;*/
@Autowired
@@ -396,6 +395,7 @@ public void update(@RequestParam(value = "id") long id, @RequestBody Tcloud tclo
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Success"),
@ApiResponse(code = 401, message = "Unauthorized"),
+ @ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Failure")})
@DeleteMapping(path="/delete")
public void delete(@RequestParam(value = "id") Long id) {
diff --git a/tcloud-client/src/main/resources/templates/jssoclient.ftl b/tcloud-client/src/main/resources/templates/jssoclient.ftl
index 822ab27..045a30e 100644
--- a/tcloud-client/src/main/resources/templates/jssoclient.ftl
+++ b/tcloud-client/src/main/resources/templates/jssoclient.ftl
@@ -133,7 +133,7 @@
function loginToken(){
// Form input values username & password
var $form = $(form_auth);
- if ($form.find('input[name="username"]').length>0 && $form.find('input[name="password"]').length>0) {
+ if ($form.find('input[name="username"]').length>0 && $form.find('input[name="password"]').length>0) {
OAuth2Client.username = $form.find('input[name="username"]').val();
OAuth2Client.password = $form.find('input[name="password"]').val();
}
@@ -278,8 +278,12 @@
function loginSSOError(xhr) {
var jsonResp = JSON.parse(xhr.responseText);
- $("#error").html(jsonResp.status+" "+jsonResp.error+" "+jsonResp.message+
- (jsonResp.error_description != undefined ? jsonResp.error_description : "")).css("color","red");
+ if (jsonResp.status != undefined && jsonResp.message != undefined && jsonResp.error != undefined) {
+ $("#error").html(jsonResp.status + " " +jsonResp.error+" "+ jsonResp.message).css("color", "red");
+ }
+ else if (jsonResp.error != undefined && jsonResp.error_description != undefined){
+ $("#error").html(jsonResp.error+" "+jsonResp.error_description).css("color","red");
+ }
}
// Ajax Client Services, attach deferred.promise(jqXHR)
diff --git a/tcloud-client/src/main/resources/templates/jssoclient.html b/tcloud-client/src/main/resources/templates/jssoclient.html
index 27700d3..4b01b84 100644
--- a/tcloud-client/src/main/resources/templates/jssoclient.html
+++ b/tcloud-client/src/main/resources/templates/jssoclient.html
@@ -133,7 +133,7 @@
function loginToken(){
// Form input values username & password
var $form = $(form_auth);
- if ($form.find('input[name="username"]').length>0 && $form.find('input[name="password"]').length>0) {
+ if ($form.find('input[name="username"]').length>0 && $form.find('input[name="password"]').length>0) {
OAuth2Client.username = $form.find('input[name="username"]').val();
OAuth2Client.password = $form.find('input[name="password"]').val();
}
@@ -287,8 +287,12 @@
function loginSSOError(xhr) {
var jsonResp = JSON.parse(xhr.responseText);
- $("#error").html(jsonResp.status+" "+jsonResp.error+" "+jsonResp.message+
- (jsonResp.error_description != undefined ? jsonResp.error_description : "")).css("color","red");
+ if (jsonResp.status != undefined && jsonResp.message != undefined && jsonResp.error != undefined) {
+ $("#error").html(jsonResp.status + " " +jsonResp.error+" "+ jsonResp.message).css("color", "red");
+ }
+ else if (jsonResp.error != undefined && jsonResp.error_description != undefined){
+ $("#error").html(jsonResp.error+" "+jsonResp.error_description).css("color","red");
+ }
}
// Ajax Client Services, attach deferred.promise(jqXHR)