authorization server setting

This commit is contained in:
tom
2019-05-16 18:28:10 +09:00
parent 77915f8317
commit 5dd491a870
15 changed files with 426 additions and 15 deletions

View File

@@ -1,6 +1,7 @@
package io.bluemoon.authorizationserver.config;
import io.bluemoon.authorizationserver.service.user.CustomUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@@ -23,29 +24,31 @@ import javax.sql.DataSource;
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
public class OAuth2SsoServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private ApprovalStore approvalStore;
private ClientDetailsService clientDetailsService;
private AuthenticationManager authenticationManager;
private DataSource dataSource;
private CustomUserDetailsServiceImpl customUserDetailsService;
public AuthServerConfig(
public OAuth2SsoServerConfig(
// AuthorizationCodeServices authorizationCodeServices,
// ApprovalStore approvalStore,
ClientDetailsService clientDetailsService,
AuthenticationManager authenticationManager,
DataSource dataSource,
CustomUserDetailsServiceImpl customUserDetailsService,
AuthorizationCodeServices authorizationCodeServices,
ApprovalStore approvalStore
CustomUserDetailsServiceImpl customUserDetailsService
) {
// this.authorizationCodeServices = authorizationCodeServices;
// this.approvalStore = approvalStore;
this.clientDetailsService = clientDetailsService;
this.authenticationManager = authenticationManager;
this.dataSource = dataSource;
this.customUserDetailsService = customUserDetailsService;
this.authorizationCodeServices = authorizationCodeServices;
this.approvalStore = approvalStore;
}
@Override
@@ -67,9 +70,9 @@ public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
// refresh token
.userDetailsService(customUserDetailsService)
// approval store
.approvalStore(jdbcApprovalStore(dataSource))
.approvalStore(approvalStore)
// code service
.authorizationCodeServices(jdbcAuthorizationCodeServices(dataSource));
.authorizationCodeServices(authorizationCodeServices);
}
@Override

View File

@@ -1,6 +1,7 @@
package io.bluemoon.authorizationserver.config;
import io.bluemoon.authorizationserver.service.user.CustomUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -11,8 +12,10 @@ import org.springframework.security.config.annotation.authentication.builders.Au
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@Configuration
@EnableResourceServer
@Order(SecurityProperties.BASIC_AUTH_ORDER - 6)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@@ -40,7 +43,19 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/oauth/**", "/test/**").permitAll();
http.authorizeRequests().antMatchers("/**").permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//
auth
.inMemoryAuthentication()
.withUser("user1").password("1234").roles("USER");
}
/**

View File

@@ -0,0 +1,71 @@
package io.bluemoon.authorizationserver.controller.sso;
import io.bluemoon.authorizationserver.domain.UserResponseWrapper;
import io.bluemoon.authorizationserver.domain.oauth.accesstoken.AccessToken;
import io.bluemoon.authorizationserver.service.sso.SsoService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
@Controller
public class SsoController {
private SsoService ssoService;
public SsoController(
SsoService ssoService
) {
this.ssoService = ssoService;
}
@RequestMapping(value = "/userInfo", method = RequestMethod.POST)
@ResponseBody
public UserResponseWrapper userResponse(
@RequestParam(name = "token") String token,
@RequestParam(name = "clientId") String clientId
) {
AccessToken accessToken = ssoService.getAccessToken(token, clientId);
UserResponseWrapper userResponseWrapper = new UserResponseWrapper();
if (accessToken == null) {
userResponseWrapper.setResult(false);
userResponseWrapper.setMessage("사용자 정보를 조회할 수 없습니다.");
} else {
userResponseWrapper.setMessage(accessToken.getUserName());
}
return userResponseWrapper;
}
@RequestMapping(value = "/userLogout", method = RequestMethod.GET)
public String userLogout(
@RequestParam(name = "clientId") String clientId,
HttpServletRequest request
) {
String userName = request.getRemoteUser();
String baseUri = ssoService.logoutAllClient(clientId, userName);
request.getSession().invalidate();
return "redirect:"+baseUri;
}
@RequestMapping(value = "/oauthCallback", method = RequestMethod.GET)
public String oauthCallback(
@RequestParam(name = "code") String code,
@RequestParam(name = "state") String state,
HttpServletRequest request, ModelMap map
) {
System.out.println(code);
System.out.println(state);
System.out.println(request);
System.out.println(map.toString());
return "aa";
}
}

View File

@@ -0,0 +1,13 @@
package io.bluemoon.authorizationserver.domain;
import lombok.Data;
@Data
public class UserResponseWrapper {
private boolean result = true;
private String message;
private String userName;
}

View File

@@ -1,4 +0,0 @@
package io.bluemoon.authorizationserver.domain.client;
public class Client {
}

View File

@@ -0,0 +1,31 @@
package io.bluemoon.authorizationserver.domain.oauth.accesstoken;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Data
@Table(name = "oauth_access_token")
public class AccessToken {
@Id
@Column(name = "token_id")
private String tokenId;
private String token;
@Column(name = "user_name")
private String userName;
@Column(name = "authentication_id")
private String authenticationId;
@Column(name = "client_id")
private String clientId;
private String authentication;
}

View File

@@ -0,0 +1,15 @@
package io.bluemoon.authorizationserver.domain.oauth.accesstoken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
public interface AccessTokenRepository extends JpaRepository<AccessToken, String> {
AccessToken findByTokenIdAndClientId(String tokenId, String clientId);
int deleteByUserName(String userName);
List<AccessToken> findByUserName(String username);
}

View File

@@ -0,0 +1,27 @@
package io.bluemoon.authorizationserver.domain.oauth.client;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Data
@Table(name = "oauth_client_details")
public class Client {
@Id
@Column(name = "client_id")
private String clientId;
@Column(name = "web_server_redirect_uri")
private String redirectUri;
@Column(name = "logout_uri")
private String logoutUri;
@Column(name = "base_uri")
private String baseUri;
}

View File

@@ -0,0 +1,7 @@
package io.bluemoon.authorizationserver.domain.oauth.client;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ClientRepository extends JpaRepository<Client, String> {
}

View File

@@ -1,6 +1,7 @@
package io.bluemoon.authorizationserver.domain.user;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUserName(String userName);

View File

@@ -0,0 +1,12 @@
package io.bluemoon.authorizationserver.service.sso;
import io.bluemoon.authorizationserver.domain.oauth.accesstoken.AccessToken;
public interface SsoService {
AccessToken getAccessToken(String token, String clientId);
String logoutAllClient(String clientId, String userName);
}

View File

@@ -0,0 +1,92 @@
package io.bluemoon.authorizationserver.service.sso;
import io.bluemoon.authorizationserver.domain.oauth.accesstoken.AccessToken;
import io.bluemoon.authorizationserver.domain.oauth.accesstoken.AccessTokenRepository;
import io.bluemoon.authorizationserver.domain.oauth.client.Client;
import io.bluemoon.authorizationserver.domain.oauth.client.ClientRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class SsoServiceImpl implements SsoService{
private AccessTokenRepository accessTokenRepository;
private ClientRepository clientRepository;
public SsoServiceImpl(
AccessTokenRepository accessTokenRepository,
ClientRepository clientRepository
) {
this.accessTokenRepository = accessTokenRepository;
this.clientRepository = clientRepository;
}
@Override
public AccessToken getAccessToken(String token, String clientId) {
String tokenId = extractTokenId(token);
return accessTokenRepository.findByTokenIdAndClientId(tokenId, clientId);
}
private String extractTokenId(String value) {
if (value == null) {
return null;
}
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bytes = digest.digest(value.getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not avilable. Fatal (should be in the JDK).");
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
@Override
@Transactional
public String logoutAllClient(String clientId, String userName) {
requestLogoutToAllClients(userName);
removeAccessToken(userName);
Optional<Client> client = clientRepository.findById(clientId);
return client.get().getBaseUri();
}
private void requestLogoutToAllClients(String userName) {
List<AccessToken> tokenList = accessTokenRepository.findByUserName(userName);
for (AccessToken token : tokenList) {
requestLogoutToClient(token);
}
}
private void requestLogoutToClient(AccessToken token) {
Optional<Client> client = clientRepository.findById(token.getClientId());
String logoutUri = client.get().getLogoutUri();
String authorizationHeader = null;
Map<String, String> paramMap = new HashMap<>();
paramMap.put("tokenId", token.getTokenId());
paramMap.put("userName", token.getUserName());
// logout 요청
}
private int removeAccessToken(String userName) {
return accessTokenRepository.deleteByUserName(userName);
}
}

View File

@@ -1,2 +1,17 @@
server.port=8081
security.oauth2.authorization.check-token-access=isAuthenticated()
security.oauth2.authorization.check-token-access=isAuthenticated()
spring.main.allow-bean-definition-overriding=true
spring.datasource.url=jdbc:mysql://127.0.0.1/oauth2?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=uneed3515
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.platform=schema
spring.jpa.database = MYSQL
#spring.jpa.hibernate.ddl-auto=update
#spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
#spring.jpa.generate-ddl=false
#spring.jpa.hibernate.ddl-auto=none

View File

@@ -0,0 +1,43 @@
insert into oauth_client_details (client_id, client_secret,
resource_ids, scope, authorized_grant_types,
web_server_redirect_uri, authorities, access_token_validity,
refresh_token_validity, additional_information,
autoapprove, logout_uri, base_uri)
values ('System1_id', 'System1_secret',
null, 'read', 'authorization_code',
'http://localhost:18010/oauthCallback', 'ROLE_YOUR_CLIENT', 36000,
2592000, null,
'true', 'http://localhost:8081/logout', 'http://localhost:8081/me');
insert into oauth_client_details (client_id, client_secret,
resource_ids, scope, authorized_grant_types,
web_server_redirect_uri, authorities, access_token_validity,
refresh_token_validity, additional_information,
autoapprove, logout_uri, base_uri)
values ('System2_id', 'System2_secret',
null, 'read', 'authorization_code',
'http://localhost:18020/oauthCallback', 'ROLE_YOUR_CLIENT', 36000,
2592000, null,
'true', 'http://localhost:18020/logout', 'http://localhost:18020/me');
insert into oauth_client_details (client_id, client_secret,
resource_ids, scope, authorized_grant_types,
web_server_redirect_uri, authorities, access_token_validity,
refresh_token_validity, additional_information,
autoapprove, logout_uri, base_uri)
values ('System3_id', 'System3_secret',
null, 'read', 'authorization_code',
'http://localhost:18030/oauthCallback', 'ROLE_YOUR_CLIENT', 36000,
2592000, null,
'true', 'http://localhost:18030/logout', 'http://localhost:18030/me');
insert into oauth_client_details (client_id, client_secret,
resource_ids, scope, authorized_grant_types,
web_server_redirect_uri, authorities, access_token_validity,
refresh_token_validity, additional_information,
autoapprove, logout_uri, base_uri)
values ('System4_id', 'System4_secret',
null, 'read', 'authorization_code',
'http://localhost:18040/oauthCallback', 'ROLE_YOUR_CLIENT', 36000,
2592000, null,
'true', 'http://localhost:18040/logout', 'http://localhost:18040/me');

View File

@@ -0,0 +1,70 @@
-- used in tests that use Mysql Local
create table oauth_client_details (
client_id VARCHAR(255) PRIMARY KEY,
resource_ids VARCHAR(255),
client_secret VARCHAR(255),
scope VARCHAR(255),
authorized_grant_types VARCHAR(255),
web_server_redirect_uri VARCHAR(255),
logout_uri VARCHAR(255),
base_uri VARCHAR(255),
authorities VARCHAR(255),
access_token_validity INTEGER,
refresh_token_validity INTEGER,
additional_information VARCHAR(4096),
autoapprove VARCHAR(255)
);
create table oauth_client_token (
token_id VARCHAR(255),
token BLOB,
authentication_id VARCHAR(255) PRIMARY KEY,
user_name VARCHAR(255),
client_id VARCHAR(255)
);
create table oauth_access_token (
token_id VARCHAR(255),
token BLOB,
authentication_id VARCHAR(255) PRIMARY KEY,
user_name VARCHAR(255),
client_id VARCHAR(255),
authentication BLOB,
refresh_token VARCHAR(255)
);
create table oauth_refresh_token (
token_id VARCHAR(255),
token BLOB,
authentication BLOB
);
create table oauth_code (
code VARCHAR(255), authentication BLOB
);
create table oauth_approvals (
userId VARCHAR(255),
clientId VARCHAR(255),
scope VARCHAR(255),
status VARCHAR(10),
expiresAt TIMESTAMP,
lastModifiedAt TIMESTAMP
);
-- -- customized oauth_client_details table
-- create table ClientDetails (
-- appId VARCHAR(255) PRIMARY KEY,
-- resourceIds VARCHAR(255),
-- appSecret VARCHAR(255),
-- scope VARCHAR(255),
-- grantTypes VARCHAR(255),
-- redirectUrl VARCHAR(255),
-- authorities VARCHAR(255),
-- access_token_validity INTEGER,
-- refresh_token_validity INTEGER,
-- additionalInformation VARCHAR(4096),
-- autoApproveScopes VARCHAR(255)
-- );