authorization server setting
This commit is contained in:
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package io.bluemoon.authorizationserver.domain.client;
|
||||
|
||||
public class Client {
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
43
authorization-server/src/main/resources/data.sql
Normal file
43
authorization-server/src/main/resources/data.sql
Normal 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');
|
||||
70
authorization-server/src/main/resources/schema.sql
Normal file
70
authorization-server/src/main/resources/schema.sql
Normal 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)
|
||||
-- );
|
||||
Reference in New Issue
Block a user