map) {
41 | MessageDigest digest;
42 | try {
43 | digest = MessageDigest.getInstance("MD5");
44 | } catch (NoSuchAlgorithmException e) {
45 | throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
46 | }
47 |
48 | try {
49 | byte[] bytes = digest.digest(map.toString().getBytes("UTF-8"));
50 | return String.format("%032x", new BigInteger(1, bytes));
51 | } catch (UnsupportedEncodingException e) {
52 | throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/others/database/initial-db.ddl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | set names utf8;
5 |
6 |
7 | -- Two users: admin/admin; test/test
8 | truncate users;
9 | insert into users(id,guid,create_time,username,password,default_user)
10 | values
11 | (21,uuid(),now(),'admin','21232f297a57a5a743894a0e4a801fc3',1),
12 | (22,uuid(),now(),'test','098f6bcd4621d373cade4e832627b4f6',0);
13 |
14 |
15 | -- Two roles: User,Admin
16 | truncate roles;
17 | insert into roles(id,guid,create_time,role_name)
18 | values
19 | (21,uuid(),now(),'Admin'),
20 | (22,uuid(),now(),'User');
21 |
22 |
23 | -- Four permissions: user:create,user:edit,user:list,user:delete
24 | truncate roles_permissions;
25 | insert into roles_permissions(roles_id, permission)
26 | values
27 | (21,'user:create'),
28 | (21,'user:edit'),
29 | (21,'user:list'),
30 | (21,'user:delete'),
31 | (22,'user:list');
32 |
33 |
34 | -- user_roles
35 | truncate user_roles;
36 | insert into user_roles(users_id,roles_id)
37 | values
38 | (21,21),
39 | (22,22);
40 |
41 |
42 |
43 |
44 | -- Initial Oauth
45 | -- oauth_client_details
46 | truncate oauth_client_details;
47 | insert into oauth_client_details(client_id, client_secret, client_name, client_uri,
48 | client_icon_uri, resource_ids, scope, grant_types,
49 | redirect_uri, roles)
50 | values
51 | ('test','test','Test Client','http://andaily.com',
52 | 'http://andaily.com/favicon.ico','os-resource','read write','authorization_code,password,refresh_token,client_credentials',
53 | 'http://localhost:7777/spring-oauth-client/authorization_code_callback','22');
54 | -- Mobile resource client details
55 | insert into oauth_client_details(client_id, client_secret, client_name, client_uri,
56 | client_icon_uri, resource_ids, scope, grant_types,
57 | redirect_uri, roles)
58 | values
59 | ('mobile','mobile','Mobile Client','http://andaily.com',
60 | 'http://andaily.com/favicon.ico','mobile-resource','read write','password,refresh_token',
61 | 'http://localhost:7777/spring-oauth-client/authorization_code_callback','22');
62 |
63 |
64 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/web/context/OAuthShiroHandlerExceptionResolver.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web.context;
2 |
3 | import com.monkeyk.os.web.WebUtils;
4 | import org.apache.oltu.oauth2.as.response.OAuthASResponse;
5 | import org.apache.oltu.oauth2.common.error.OAuthError;
6 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
7 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
8 | import org.apache.shiro.authz.AuthorizationException;
9 | import org.apache.shiro.authz.UnauthorizedException;
10 | import org.springframework.web.servlet.HandlerExceptionResolver;
11 | import org.springframework.web.servlet.ModelAndView;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 |
16 | /**
17 | * 2015/9/29
18 | *
19 | * @author Shengzhao Li
20 | */
21 | public class OAuthShiroHandlerExceptionResolver implements HandlerExceptionResolver {
22 |
23 |
24 | public OAuthShiroHandlerExceptionResolver() {
25 | }
26 |
27 | @Override
28 | public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
29 |
30 | if (ex instanceof UnauthorizedException) {
31 | handleUnauthorizedException(response, ex);
32 | } else if (ex instanceof AuthorizationException) {
33 | handleUnauthorizedException(response, ex);
34 | }
35 | //more
36 |
37 | return null;
38 | }
39 |
40 | private void handleUnauthorizedException(HttpServletResponse response, Exception ex) {
41 | OAuthResponse oAuthResponse;
42 | try {
43 | oAuthResponse = OAuthASResponse.errorResponse(403)
44 | .setError(OAuthError.ResourceResponse.INVALID_TOKEN)
45 | .setErrorDescription(ex.getMessage())
46 | .buildJSONMessage();
47 | } catch (OAuthSystemException e) {
48 | throw new IllegalStateException(e);
49 | }
50 |
51 | WebUtils.writeOAuthJsonResponse(response, oAuthResponse);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/resources/src/main/java/com/monkeyk/os/web/context/OAuthShiroHandlerExceptionResolver.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web.context;
2 |
3 | import com.monkeyk.os.web.WebUtils;
4 | import org.apache.oltu.oauth2.common.error.OAuthError;
5 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
6 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
7 | import org.apache.oltu.oauth2.rs.response.OAuthRSResponse;
8 | import org.apache.shiro.authz.AuthorizationException;
9 | import org.apache.shiro.authz.UnauthorizedException;
10 | import org.springframework.web.servlet.HandlerExceptionResolver;
11 | import org.springframework.web.servlet.ModelAndView;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 |
16 | /**
17 | * 2015/9/29
18 | *
19 | * @author Shengzhao Li
20 | */
21 | public class OAuthShiroHandlerExceptionResolver implements HandlerExceptionResolver {
22 |
23 |
24 | public OAuthShiroHandlerExceptionResolver() {
25 | }
26 |
27 | @Override
28 | public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
29 |
30 | if (ex instanceof UnauthorizedException) {
31 | handleUnauthorizedException(response, ex);
32 | } else if (ex instanceof AuthorizationException) {
33 | handleUnauthorizedException(response, ex);
34 | }
35 | //more
36 |
37 | return null;
38 | }
39 |
40 | private void handleUnauthorizedException(HttpServletResponse response, Exception ex) {
41 | OAuthResponse oAuthResponse;
42 | try {
43 | oAuthResponse = OAuthRSResponse.errorResponse(403)
44 | .setError(OAuthError.ResourceResponse.INVALID_TOKEN)
45 | .setErrorDescription(ex.getMessage())
46 | .buildJSONMessage();
47 | } catch (OAuthSystemException e) {
48 | throw new IllegalStateException(e);
49 | }
50 |
51 | WebUtils.writeOAuthJsonResponse(response, oAuthResponse);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/authorize/CodeAuthorizeHandler.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.oauth.authorize;
2 |
3 | import com.monkeyk.os.domain.oauth.ClientDetails;
4 | import com.monkeyk.os.web.WebUtils;
5 | import com.monkeyk.os.oauth.OAuthAuthxRequest;
6 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
7 | import com.monkeyk.os.oauth.validator.CodeClientDetailsValidator;
8 | import org.apache.oltu.oauth2.as.response.OAuthASResponse;
9 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
10 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import javax.servlet.http.HttpServletResponse;
15 | import java.io.IOException;
16 |
17 | /**
18 | * 2015/6/25
19 | *
20 | * Handle response_type = 'code'
21 | *
22 | * @author Shengzhao Li
23 | */
24 | public class CodeAuthorizeHandler extends AbstractAuthorizeHandler {
25 |
26 | private static final Logger LOG = LoggerFactory.getLogger(CodeAuthorizeHandler.class);
27 |
28 |
29 | public CodeAuthorizeHandler(OAuthAuthxRequest oauthRequest, HttpServletResponse response) {
30 | super(oauthRequest, response);
31 | }
32 |
33 | @Override
34 | protected AbstractClientDetailsValidator getValidator() {
35 | return new CodeClientDetailsValidator(oauthRequest);
36 | }
37 |
38 |
39 | //response code
40 | @Override
41 | protected void handleResponse() throws OAuthSystemException, IOException {
42 | final ClientDetails clientDetails = clientDetails();
43 | final String authCode = oauthService.retrieveAuthCode(clientDetails);
44 |
45 | final OAuthResponse oAuthResponse = OAuthASResponse
46 | .authorizationResponse(oauthRequest.request(), HttpServletResponse.SC_OK)
47 | .location(clientDetails.redirectUri())
48 | .setCode(authCode)
49 | .buildQueryMessage();
50 | LOG.debug(" 'code' response: {}", oAuthResponse);
51 |
52 | WebUtils.writeOAuthQueryResponse(response, oAuthResponse);
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/web/controller/OauthTokenController.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web.controller;
2 |
3 | import com.monkeyk.os.web.WebUtils;
4 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
5 | import com.monkeyk.os.oauth.token.OAuthTokenHandleDispatcher;
6 | import org.apache.oltu.oauth2.as.response.OAuthASResponse;
7 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
8 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 |
12 | import javax.servlet.http.HttpServletRequest;
13 | import javax.servlet.http.HttpServletResponse;
14 |
15 | /**
16 | * 2015/7/3
17 | *
18 | * URL: oauth/token
19 | *
20 | * @author Shengzhao Li
21 | */
22 | @Controller
23 | @RequestMapping("oauth/")
24 | public class OauthTokenController {
25 |
26 |
27 | /**
28 | * Handle grant_types as follows:
29 | *
30 | * grant_type=authorization_code
31 | * grant_type=password
32 | * grant_type=refresh_token
33 | * grant_type=client_credentials
34 | *
35 | * @param request HttpServletRequest
36 | * @param response HttpServletResponse
37 | * @throws Exception
38 | */
39 | @RequestMapping("token")
40 | public void authorize(HttpServletRequest request, HttpServletResponse response) throws Exception {
41 | try {
42 | OAuthTokenxRequest tokenRequest = new OAuthTokenxRequest(request);
43 |
44 | OAuthTokenHandleDispatcher tokenHandleDispatcher = new OAuthTokenHandleDispatcher(tokenRequest, response);
45 | tokenHandleDispatcher.dispatch();
46 |
47 | } catch (OAuthProblemException e) {
48 | //exception
49 | OAuthResponse oAuthResponse = OAuthASResponse
50 | .errorResponse(HttpServletResponse.SC_FOUND)
51 | .location(e.getRedirectUri())
52 | .error(e)
53 | .buildJSONMessage();
54 | WebUtils.writeOAuthJsonResponse(response, oAuthResponse);
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/monkeyk/os/domain/users/Users.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.domain.users;
13 |
14 | import com.monkeyk.os.domain.AbstractDomain;
15 | import com.monkeyk.os.domain.AbstractIdDomain;
16 | import com.monkeyk.os.domain.shared.GuidGenerator;
17 |
18 | import java.util.Date;
19 |
20 | /**
21 | * 2015/10/26
22 | *
23 | * Table: users
24 | *
25 | * @author Shengzhao Li
26 | */
27 | public class Users extends AbstractIdDomain {
28 |
29 |
30 | private static final long serialVersionUID = -3990278799194556012L;
31 |
32 |
33 | //unique
34 | private String username;
35 |
36 | private String password;
37 |
38 | /**
39 | * Label default user or not
40 | */
41 | private boolean defaultUser = false;
42 |
43 |
44 | private Date lastLoginTime;
45 |
46 |
47 | public Users() {
48 | }
49 |
50 | public String username() {
51 | return username;
52 | }
53 |
54 | public Users username(String username) {
55 | this.username = username;
56 | return this;
57 | }
58 |
59 | public String password() {
60 | return password;
61 | }
62 |
63 | public Users password(String password) {
64 | this.password = password;
65 | return this;
66 | }
67 |
68 | public boolean defaultUser() {
69 | return defaultUser;
70 | }
71 |
72 | public Users defaultUser(boolean defaultUser) {
73 | this.defaultUser = defaultUser;
74 | return this;
75 | }
76 |
77 | public Date lastLoginTime() {
78 | return lastLoginTime;
79 | }
80 |
81 | public Users lastLoginTime(Date lastLoginTime) {
82 | this.lastLoginTime = lastLoginTime;
83 | return this;
84 | }
85 |
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/AbstractAccessTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.AuthenticationIdGenerator;
16 | import com.monkeyk.os.domain.oauth.ClientDetails;
17 | import com.monkeyk.os.domain.shared.BeanProvider;
18 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
19 | import org.slf4j.Logger;
20 | import org.slf4j.LoggerFactory;
21 | import org.springframework.util.Assert;
22 |
23 | /**
24 | * 2015/10/22
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public abstract class AbstractAccessTokenHandler extends AbstractOAuthHolder {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(AbstractAccessTokenHandler.class);
31 |
32 |
33 | protected transient AuthenticationIdGenerator authenticationIdGenerator = BeanProvider.getBean(AuthenticationIdGenerator.class);
34 |
35 |
36 | protected AccessToken createAndSaveAccessToken(ClientDetails clientDetails, boolean includeRefreshToken, String username, String authenticationId) throws OAuthSystemException {
37 | Assert.notNull(username, "username is null");
38 | AccessToken accessToken = new AccessToken()
39 | .clientId(clientDetails.clientId())
40 | .username(username)
41 | .tokenId(oAuthIssuer.accessToken())
42 | .authenticationId(authenticationId)
43 | .updateByClientDetails(clientDetails);
44 |
45 | if (includeRefreshToken) {
46 | accessToken.refreshToken(oAuthIssuer.refreshToken());
47 | }
48 |
49 | this.oauthRepository.saveAccessToken(accessToken);
50 | LOG.debug("Save AccessToken: {}", accessToken);
51 | return accessToken;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #oauth2-shiro-redis
2 |
3 |
4 | Integrate oauth2-shiro with Redis
5 |
6 |
7 | GitHub地址: https://github.com/monkeyk/oauth2-shiro
8 |
9 |
10 |
11 |
12 |
说明
13 |
该项目具有 oauth2-shiro 的所有功能, 并添加了对 Redis 的支持
14 |
从 oauth2-shiro fork 的版本: 0.1-rc
15 |
项目使用的 Redis 版本信息
16 |
17 | spring-data-redis -> 1.5.2.RELEASE
18 |
19 | jedis -> 2.7.3
20 |
21 |
22 |
23 |
24 |
25 |
26 |
功能变化
27 |
相比 oauth2-shiro 项目, 添加并支持更多的功能与配置
28 |
29 | 支持Redis连接属性更多的设置, 详见配置文件 resources.properties, authz.properties
30 | 提供对 ClientDetails 的操作支持, 详见 ClientDetailsService.java
31 | 重构 ClientDetails, 使其支持 序列化(Serializable)
32 | 添加配置属性 remove.token.expired, 支持当检测到 access_token 过期时删除对应的 AccessToken 数据
33 | 根据需要可去掉MYSQL数据库支持, 只使用Redis, 详见 branch: redis
34 | 重构 OAUTH2 业务实现的代码, 使结构,代码更清晰, 可读更强
35 |
36 |
37 |
38 |
39 |
40 |
使用注意
41 |
authz 与 resources 模块中配置的 Redis 必须是同一个Redis的连接信息, 方可正常工作
42 |
在项目中,使用Redis做缓存, 提高性能,同时也将数据存入MYSQL数据库; 也支持去掉MYSQL,只使用Redis(需要修改配置实现)
43 |
44 |
45 |
46 |
47 |
48 |
Project Logs
49 |
记录项目的变化与发展历程
50 |
51 |
52 | 2015-10-21 从oauth2-shiro fork源代码到本项目中
53 | 2015-10-27 创建branch: redis, 只支持Redis操作
54 | 2016-07-08 oauth2-shiro-redis 开源
55 | 2017-01-21 加入GitHub https://github.com/monkeyk/oauth2-shiro-redis
56 |
57 |
58 |
59 |
60 |
61 |
技术支持联系方式
62 |
Email: sz@monkeyk.com
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/OauthService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import com.monkeyk.os.domain.oauth.OauthCode;
17 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
18 |
19 | import java.util.Set;
20 |
21 | /**
22 | * 15-6-10
23 | *
24 | * @author Shengzhao Li
25 | */
26 | public interface OauthService {
27 |
28 | ClientDetails loadClientDetails(String clientId);
29 |
30 | String retrieveAuthCode(ClientDetails clientDetails) throws OAuthSystemException;
31 |
32 | AccessToken retrieveAccessToken(ClientDetails clientDetails, Set scopes, boolean includeRefreshToken) throws OAuthSystemException;
33 |
34 | //Always return new AccessToken, exclude refreshToken
35 | AccessToken retrieveNewAccessToken(ClientDetails clientDetails, Set scopes) throws OAuthSystemException;
36 |
37 | OauthCode loadOauthCode(String code, ClientDetails clientDetails);
38 |
39 | boolean removeOauthCode(String code, ClientDetails clientDetails);
40 |
41 | //Always return new AccessToken
42 | AccessToken retrieveAuthorizationCodeAccessToken(ClientDetails clientDetails, String code) throws OAuthSystemException;
43 |
44 | //grant_type=password AccessToken
45 | AccessToken retrievePasswordAccessToken(ClientDetails clientDetails, Set scopes, String username) throws OAuthSystemException;
46 |
47 | //grant_type=client_credentials
48 | AccessToken retrieveClientCredentialsAccessToken(ClientDetails clientDetails, Set scopes) throws OAuthSystemException;
49 |
50 | AccessToken loadAccessTokenByRefreshToken(String refreshToken, String clientId);
51 |
52 | AccessToken changeAccessTokenByRefreshToken(String refreshToken, String clientId) throws OAuthSystemException;
53 | }
54 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/AccessTokenRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.utils.OAuthUtils;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/10/22
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class AccessTokenRetriever extends AbstractAccessTokenHandler {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(AccessTokenRetriever.class);
31 |
32 | private final ClientDetails clientDetails;
33 | private final Set scopes;
34 | private final boolean includeRefreshToken;
35 |
36 | public AccessTokenRetriever(ClientDetails clientDetails, Set scopes, boolean includeRefreshToken) {
37 | this.clientDetails = clientDetails;
38 | this.scopes = scopes;
39 | this.includeRefreshToken = includeRefreshToken;
40 | }
41 |
42 | public AccessToken retrieve() throws OAuthSystemException {
43 |
44 | String scope = OAuthUtils.encodeScopes(scopes);
45 | final String username = currentUsername();
46 | final String clientId = clientDetails.clientId();
47 |
48 | final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
49 |
50 | AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
51 | if (accessToken == null) {
52 | accessToken = createAndSaveAccessToken(clientDetails, includeRefreshToken, username, authenticationId);
53 | LOG.debug("Create a new AccessToken: {}", accessToken);
54 | }
55 |
56 | return accessToken;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/infrastructure/jdbc/UsersJdbcRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.infrastructure.jdbc;
13 |
14 | import com.monkeyk.os.domain.users.*;
15 | import org.springframework.stereotype.Repository;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * 2015/10/26
21 | *
22 | * @author Shengzhao Li
23 | */
24 | @Repository("usersJdbcRepository")
25 | public class UsersJdbcRepository extends AbstractJdbcRepository implements UsersRepository {
26 |
27 |
28 | private static UsersRowMapper usersRowMapper = new UsersRowMapper();
29 |
30 | private static RolesRowMapper rolesRowMapper = new RolesRowMapper();
31 |
32 | private RolesPermissionsRowMapper rolesPermissionsRowMapper = new RolesPermissionsRowMapper();
33 |
34 |
35 | @Override
36 | public Users findUsersByUsername(String username) {
37 | final String sql = " select u.* from users u where u.archived = false and u.username = ? ";
38 | final List usersList = jdbcTemplate.query(sql, usersRowMapper, username);
39 | return usersList.isEmpty() ? null : usersList.get(0);
40 | }
41 |
42 |
43 | @Override
44 | public List findRolesByUsername(String username) {
45 | final String roleSql = " select r.* from roles r, user_roles ur, users u where u.archived = false " +
46 | " and u.id = ur.users_id and ur.roles_id = r.id and u.username = ? ";
47 | final List rolesList = jdbcTemplate.query(roleSql, rolesRowMapper, username);
48 |
49 | //load permissions
50 | for (Roles roles : rolesList) {
51 | loadRolesPermissions(roles);
52 | }
53 |
54 | return rolesList;
55 | }
56 |
57 | private void loadRolesPermissions(Roles roles) {
58 | final String pSql = " select p.* from roles_permissions p where p.roles_id = ? ";
59 | final List list = jdbcTemplate.query(pSql, rolesPermissionsRowMapper, roles.id());
60 | roles.permissions().addAll(list);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core/src/main/java/com/monkeyk/os/domain/AbstractIdDomain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.domain;
13 |
14 | import com.monkeyk.os.domain.shared.GuidGenerator;
15 |
16 | /**
17 | * 2015/10/26
18 | *
19 | *
20 | * Add id, version field and so on
21 | * 扩展 AbstractDomain 的抽象类, 增加 字段id, version, archived, guid
22 | *
23 | * @author Shengzhao Li
24 | */
25 | public abstract class AbstractIdDomain extends AbstractDomain {
26 |
27 | private static final long serialVersionUID = 4653514788456221527L;
28 |
29 |
30 | protected int id;
31 |
32 | /*
33 | * 实现数据 乐观锁
34 | * */
35 | // Optimistic lock
36 | protected int version = 0;
37 |
38 | /**
39 | * 数据逻辑删除的 标记
40 | */
41 | // logic delete label
42 | protected boolean archived = false;
43 |
44 | /**
45 | * 数据业务ID
46 | */
47 | // business id
48 | protected String guid = GuidGenerator.generate();
49 |
50 |
51 | public AbstractIdDomain() {
52 | }
53 |
54 | public int id() {
55 | return id;
56 | }
57 |
58 | @SuppressWarnings("unchecked")
59 | public T id(int id) {
60 | this.id = id;
61 | return (T) this;
62 | }
63 |
64 | public int version() {
65 | return version;
66 | }
67 |
68 | @SuppressWarnings("unchecked")
69 | public T version(int version) {
70 | this.version = version;
71 | return (T) this;
72 | }
73 |
74 | public boolean archived() {
75 | return archived;
76 | }
77 |
78 | @SuppressWarnings("unchecked")
79 | public T archived(boolean archived) {
80 | this.archived = archived;
81 | return (T) this;
82 | }
83 |
84 | public String guid() {
85 | return guid;
86 | }
87 |
88 | @SuppressWarnings("unchecked")
89 | public T guid(String guid) {
90 | this.guid = guid;
91 | return (T) this;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/AuthCodeRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.ClientDetails;
15 | import com.monkeyk.os.domain.oauth.OauthCode;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | /**
21 | * 2015/10/22
22 | *
23 | * @author Shengzhao Li
24 | */
25 | public class AuthCodeRetriever extends AbstractOAuthHolder {
26 |
27 | private static final Logger LOG = LoggerFactory.getLogger(AuthCodeRetriever.class);
28 |
29 |
30 |
31 | private ClientDetails clientDetails;
32 |
33 | public AuthCodeRetriever(ClientDetails clientDetails) {
34 | this.clientDetails = clientDetails;
35 | }
36 |
37 | public String retrieve() throws OAuthSystemException {
38 |
39 | final String clientId = clientDetails.clientId();
40 | final String username = currentUsername();
41 |
42 | OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(username, clientId);
43 | if (oauthCode != null) {
44 | //Always delete exist
45 | LOG.debug("OauthCode ({}) is existed, remove it and create a new one", oauthCode);
46 | oauthRepository.deleteOauthCode(oauthCode);
47 | }
48 | //create a new one
49 | oauthCode = createOauthCode();
50 |
51 | return oauthCode.code();
52 | }
53 |
54 |
55 | private OauthCode createOauthCode() throws OAuthSystemException {
56 | final String authCode = oAuthIssuer.authorizationCode();
57 |
58 | LOG.debug("Save OauthCode authorizationCode '{}' of ClientDetails '{}'", authCode, clientDetails);
59 | final String username = currentUsername();
60 | OauthCode oauthCode = new OauthCode().code(authCode).username(username).clientId(clientDetails.clientId());
61 |
62 | oauthRepository.saveOauthCode(oauthCode);
63 | return oauthCode;
64 | }
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/resources/src/main/webapp/WEB-INF/mkk-servlet.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
45 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/authz/src/main/resources/spring/authz-redis.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/resources/src/main/resources/spring/rs-redis.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/web/controller/ShiroController.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web.controller;
2 |
3 | import com.monkeyk.os.service.dto.LoginDto;
4 | import org.apache.shiro.SecurityUtils;
5 | import org.apache.shiro.authc.UsernamePasswordToken;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.stereotype.Controller;
9 | import org.springframework.ui.Model;
10 | import org.springframework.validation.BindingResult;
11 | import org.springframework.web.bind.annotation.ModelAttribute;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RequestMethod;
14 |
15 | /**
16 | * 15-6-10
17 | *
18 | * Just test Shiro
19 | *
20 | * @author Shengzhao Li
21 | */
22 | @Controller
23 | public class ShiroController {
24 |
25 | private static final Logger LOG = LoggerFactory.getLogger(ShiroController.class);
26 |
27 |
28 | @RequestMapping("index")
29 | public String index() {
30 | return "index";
31 | }
32 |
33 | @RequestMapping("unauthorized")
34 | public String unauthorized() {
35 | return "unauthorized";
36 | }
37 |
38 | /*
39 | * Logout
40 | */
41 | // @RequestMapping("logout")
42 | // public String logout() {
43 | // final Subject subject = SecurityUtils.getSubject();
44 | // LOG.debug("{} is logout", subject.getPrincipal());
45 | // subject.logout();
46 | // return "redirect:/";
47 | // }
48 |
49 | /*
50 | * Go login page
51 | */
52 | @RequestMapping(value = "login", method = RequestMethod.GET)
53 | public String login(Model model) {
54 | final LoginDto loginDto = new LoginDto();
55 | //TODO: Just testing
56 | loginDto.setUsername("test");
57 |
58 | model.addAttribute("formDto", loginDto);
59 | return "login";
60 | }
61 |
62 | @RequestMapping(value = "login", method = RequestMethod.POST)
63 | public String login(@ModelAttribute("formDto") LoginDto formDto, BindingResult errors) {
64 |
65 | UsernamePasswordToken token = formDto.token();
66 | token.setRememberMe(false);
67 |
68 | try {
69 | SecurityUtils.getSubject().login(token);
70 | } catch (Exception e) {
71 | LOG.debug("Error authenticating.", e);
72 | errors.rejectValue("username", null, "The username or password was not correct.");
73 | return "login";
74 | }
75 |
76 | return "redirect:index";
77 | }
78 |
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/authz/src/main/webapp/WEB-INF/mkk-servlet.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
46 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/others/oauth_test.txt:
--------------------------------------------------------------------------------
1 |
2 | Make sure project modules context path as below:
3 | authz -> authz
4 | resources -> rs
5 |
6 |
7 | -- Test grant_type = 'authorization_code' , get code
8 |
9 | http://localhost:8080/authz/oauth/authorize?response_type=code&scope=read write&client_id=test&redirect_uri=http%3A%2F%2Flocalhost%3A7777%2Fspring-oauth-client%2Fauthorization_code_callback&state=09876999
10 |
11 | http://localhost:8080/authz/oauth/authorize?response_type=code&scope=read%20write&client_id=test&redirect_uri=http%3A%2F%2Flocalhost%3A7777%2Fspring-oauth-client%2Fauthorization_code_callback&state=swss58522555
12 |
13 |
14 | -- Test grant_type = 'token'
15 | -- implicit
16 |
17 | http://localhost:8080/authz/oauth/authorize?response_type=token&scope=read write&client_id=test&client_secret=test&redirect_uri=http%3A%2F%2Flocalhost%3A7777%2Fspring-oauth-client%2Fauthorization_code_callback
18 |
19 |
20 | -- Test from 'code' get 'token' [POST]
21 | http://localhost:8080/authz/oauth/token?client_id=test&client_secret=test&grant_type=authorization_code&code=ac0bd18863b07adfb518cc6e6dfcfcab&redirect_uri=http://localhost:8080/os/oauth/authorize?response_type=code&scope=read%20write&client_id=test&redirect_uri=http%3A%2F%2Flocalhost%3A7777%2Fspring-oauth-client%2Fauthorization_code_callback&state=09876999
22 |
23 |
24 |
25 | -- Test grant_type='password' [POST]
26 | http://localhost:8080/authz/oauth/token?client_id=test&client_secret=test&grant_type=password&scope=read write&username=test&password=test
27 |
28 |
29 |
30 | -- Test grant_type='client_credentials' [POST]
31 | http://localhost:8080/authz/oauth/token?client_id=test&client_secret=test&grant_type=client_credentials&scope=read
32 |
33 |
34 | -- Test grant_type='refresh_token' [POST]
35 | http://localhost:8080/authz/oauth/token?client_id=test&client_secret=test&grant_type=refresh_token&refresh_token=b36f4978a1724aa8af8960f58abe3ba1
36 |
37 |
38 |
39 | --
40 | Test-Page URL: http://localhost:8080/authz/resources/oauth_test.html
41 | --
42 |
43 |
44 | --注意: scope是用空格分隔的, 如:read write
45 |
46 |
47 |
48 | -- Test resource
49 | http://localhost:8080/rs/rs/username?access_token=6b7b0726e603cd04c797d5b28c7be4c4
50 |
51 |
52 | --
53 | -- Mobile Resource
54 | --
55 |
56 | -- Test grant_type='password' [POST]
57 | http://localhost:8080/authz/oauth/token?client_id=mobile&client_secret=mobile&grant_type=password&scope=read write&username=test&password=test
58 |
59 |
60 |
61 | -- Test mobile resource
62 | http://qc8.cc:8080/rs/mobile/system_time?access_token=b69c2f61212780c901e69cebd6854667
63 |
64 |
65 |
--------------------------------------------------------------------------------
/core/src/main/java/com/monkeyk/os/infrastructure/cache/AbstractCacheSupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.infrastructure.cache;
13 |
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import org.springframework.cache.Cache;
17 |
18 | /**
19 | * 2015/10/26
20 | *
21 | * 公共类,将常用 的缓存操作放置于此
22 | *
23 | * @author Shengzhao Li
24 | */
25 | public abstract class AbstractCacheSupport {
26 |
27 |
28 | private static final Logger LOG = LoggerFactory.getLogger(AbstractCacheSupport.class);
29 |
30 |
31 | /**
32 | * 从指定的缓存中获取缓存数据
33 | *
34 | * @param cache Cache
35 | * @param key Cache key
36 | * @return Cache value
37 | */
38 | protected Object getFromCache(Cache cache, String key) {
39 | final Cache.ValueWrapper valueWrapper = cache.get(key);
40 | return valueWrapper == null ? null : valueWrapper.get();
41 | }
42 |
43 |
44 | /**
45 | * 向缓存中添加 缓存数据
46 | *
47 | * @param cache Cache
48 | * @param key Cache key
49 | * @param value Cache value, null will return false
50 | * @return True is successful,otherwise false
51 | */
52 | protected boolean putToCache(Cache cache, Object key, Object value) {
53 | if (value == null) {
54 | LOG.debug("Ignore put to cache[{}], key = {}, because value is null", cache, key);
55 | return false;
56 | }
57 | cache.put(key, value);
58 | LOG.debug("Put [{} = {}] to cache[{}]", key, value, cache);
59 | return true;
60 | }
61 |
62 |
63 | /**
64 | * 清除缓存中具体的 缓存数据
65 | *
66 | * @param cache Cache
67 | * @param key Cache key
68 | * @return True is evict successful
69 | */
70 | protected boolean evictFromCache(Cache cache, Object key) {
71 | if (key == null) {
72 | LOG.debug("Ignore evict from cache[{}], because key is null", cache);
73 | return false;
74 | }
75 | cache.evict(key);
76 | LOG.debug("Evict key[{}] from cache[{}]", key, cache);
77 | return true;
78 | }
79 |
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/OAuthTokenHandleDispatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
15 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | import javax.servlet.http.HttpServletResponse;
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * 2015/7/3
26 | *
27 | * @author Shengzhao Li
28 | */
29 | public class OAuthTokenHandleDispatcher {
30 |
31 | private static final Logger LOG = LoggerFactory.getLogger(OAuthTokenHandleDispatcher.class);
32 |
33 | private List handlers = new ArrayList<>();
34 |
35 | private final OAuthTokenxRequest tokenRequest;
36 | private final HttpServletResponse response;
37 |
38 | public OAuthTokenHandleDispatcher(OAuthTokenxRequest tokenRequest, HttpServletResponse response) {
39 | this.tokenRequest = tokenRequest;
40 | this.response = response;
41 |
42 | initialHandlers();
43 | }
44 |
45 | private void initialHandlers() {
46 | handlers.add(new AuthorizationCodeTokenHandler());
47 | handlers.add(new PasswordTokenHandler());
48 | handlers.add(new RefreshTokenHandler());
49 |
50 | handlers.add(new ClientCredentialsTokenHandler());
51 |
52 | LOG.debug("Initialed '{}' OAuthTokenHandler(s): {}", handlers.size(), handlers);
53 | }
54 |
55 |
56 | public void dispatch() throws OAuthProblemException, OAuthSystemException {
57 | for (OAuthTokenHandler handler : handlers) {
58 | if (handler.support(tokenRequest)) {
59 | LOG.debug("Found '{}' handle OAuthTokenxRequest: {}", handler, tokenRequest);
60 | handler.handle(tokenRequest, response);
61 | return;
62 | }
63 | }
64 | throw new IllegalStateException("Not found 'OAuthTokenHandler' to handle OAuthTokenxRequest: " + tokenRequest);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/authz/src/main/webapp/WEB-INF/jsp/oauth/oauth_login.jsp:
--------------------------------------------------------------------------------
1 | <%--
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | --%>
12 | <%--
13 | *
14 | * @author Shengzhao Li
15 | --%>
16 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
17 | <%@ include file="../comm-header.jsp" %>
18 |
19 |
20 |
21 | Oauth Login
22 |
23 |
24 |
25 |
26 |
Oauth Login
27 |
28 |
29 | Login for client_id: '${param.client_id}'.
30 |
31 |
32 |
48 |
49 |
50 |
51 |
You can use the users to login as follow:
52 |
53 |
54 |
55 | | username |
56 | password |
57 | grant_types |
58 | roles |
59 |
60 |
61 |
62 |
63 | | test |
64 | test |
65 | authorization_code,password,refresh_token,client_credentials |
66 | User(id=22) |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/AuthorizationCodeAccessTokenRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import com.monkeyk.os.domain.oauth.OauthCode;
17 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | /**
22 | * 2015/10/26
23 | *
24 | * @author Shengzhao Li
25 | */
26 | public class AuthorizationCodeAccessTokenRetriever extends AbstractAccessTokenHandler {
27 |
28 |
29 | private static final Logger LOG = LoggerFactory.getLogger(AuthorizationCodeAccessTokenRetriever.class);
30 |
31 |
32 | private ClientDetails clientDetails;
33 | private String code;
34 |
35 | public AuthorizationCodeAccessTokenRetriever(ClientDetails clientDetails, String code) {
36 | this.clientDetails = clientDetails;
37 | this.code = code;
38 | }
39 |
40 |
41 | //Always return new AccessToken
42 | public AccessToken retrieve() throws OAuthSystemException {
43 |
44 | final OauthCode oauthCode = loadOauthCode();
45 | final String username = oauthCode.username();
46 |
47 | final String clientId = clientDetails.clientId();
48 | final String authenticationId = authenticationIdGenerator.generate(clientId, username, null);
49 |
50 | AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
51 | if (accessToken != null) {
52 | LOG.debug("Delete existed AccessToken: {}", accessToken);
53 | oauthRepository.deleteAccessToken(accessToken);
54 | }
55 | accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
56 | LOG.debug("Create a new AccessToken: {}", accessToken);
57 |
58 | return accessToken;
59 | }
60 |
61 | private OauthCode loadOauthCode() {
62 | final String clientId = clientDetails.clientId();
63 | return oauthRepository.findOauthCode(code, clientId);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/resources/src/main/java/com/monkeyk/os/infrastructure/jdbc/UsersRSJdbcRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.infrastructure.jdbc;
13 |
14 | import com.monkeyk.os.domain.users.Roles;
15 | import com.monkeyk.os.domain.users.RolesPermissions;
16 | import com.monkeyk.os.domain.users.Users;
17 | import com.monkeyk.os.domain.users.UsersRepository;
18 | import org.springframework.stereotype.Repository;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * 2015/10/27
24 | *
25 | * @author Shengzhao Li
26 | */
27 | @Repository("usersRSJdbcRepository")
28 | public class UsersRSJdbcRepository extends AbstractJdbcRepository implements UsersRepository {
29 |
30 |
31 | private static UsersRowMapper usersRowMapper = new UsersRowMapper();
32 |
33 | private static RolesRowMapper rolesRowMapper = new RolesRowMapper();
34 |
35 | private RolesPermissionsRowMapper rolesPermissionsRowMapper = new RolesPermissionsRowMapper();
36 |
37 |
38 | @Override
39 | public Users findUsersByUsername(String username) {
40 | final String sql = " select u.* from users u where u.archived = false and u.username = ? ";
41 | final List usersList = jdbcTemplate.query(sql, usersRowMapper, username);
42 | return usersList.isEmpty() ? null : usersList.get(0);
43 | }
44 |
45 |
46 | @Override
47 | public List findRolesByUsername(String username) {
48 | final String roleSql = " select r.* from roles r, user_roles ur, users u where u.archived = false " +
49 | " and u.id = ur.users_id and ur.roles_id = r.id and u.username = ? ";
50 | final List rolesList = jdbcTemplate.query(roleSql, rolesRowMapper, username);
51 |
52 | //load permissions
53 | for (Roles roles : rolesList) {
54 | loadRolesPermissions(roles);
55 | }
56 |
57 | return rolesList;
58 | }
59 |
60 | private void loadRolesPermissions(Roles roles) {
61 | final String pSql = " select p.* from roles_permissions p where p.roles_id = ? ";
62 | final List list = jdbcTemplate.query(pSql, rolesPermissionsRowMapper, roles.id());
63 | roles.permissions().addAll(list);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/validator/TokenClientDetailsValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.validator;
13 |
14 | import com.monkeyk.os.domain.oauth.ClientDetails;
15 | import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 15-6-13
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class TokenClientDetailsValidator extends AbstractClientDetailsValidator {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(TokenClientDetailsValidator.class);
31 |
32 |
33 | public TokenClientDetailsValidator(OAuthAuthzRequest oauthRequest) {
34 | super(oauthRequest);
35 | }
36 |
37 | /*
38 | * grant_type="implicit" -> response_type="token"
39 | * ?response_type=token&scope=read,write&client_id=[client_id]&client_secret=[client_secret]&redirect_uri=[redirect_uri]
40 | * */
41 | @Override
42 | public OAuthResponse validateSelf(ClientDetails clientDetails) throws OAuthSystemException {
43 |
44 | //validate client_secret
45 | final String clientSecret = oauthRequest.getClientSecret();
46 | if (clientSecret == null || !clientSecret.equals(clientDetails.clientSecret())) {
47 | return invalidClientSecretResponse();
48 | }
49 |
50 | //validate redirect_uri
51 | final String redirectURI = oauthRequest.getRedirectURI();
52 | if (redirectURI == null || !redirectURI.equals(clientDetails.redirectUri())) {
53 | LOG.debug("Invalid redirect_uri '{}' by response_type = 'code', client_id = '{}'", redirectURI, clientDetails.clientId());
54 | return invalidRedirectUriResponse();
55 | }
56 |
57 | //validate scope
58 | final Set scopes = oauthRequest.getScopes();
59 | if (scopes.isEmpty() || excludeScopes(scopes, clientDetails)) {
60 | return invalidScopeResponse();
61 | }
62 |
63 |
64 | return null;
65 | }
66 |
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/validator/ClientCredentialsClientDetailsValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.validator;
13 |
14 | import com.monkeyk.os.domain.oauth.ClientDetails;
15 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/7/5
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class ClientCredentialsClientDetailsValidator extends AbstractOauthTokenValidator {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(ClientCredentialsClientDetailsValidator.class);
31 |
32 |
33 | public ClientCredentialsClientDetailsValidator(OAuthTokenxRequest oauthRequest) {
34 | super(oauthRequest);
35 | }
36 |
37 | /*
38 | * /oauth/token?client_id=credentials-client&client_secret=credentials-secret&grant_type=client_credentials&scope=read write
39 | * */
40 | @Override
41 | protected OAuthResponse validateSelf(ClientDetails clientDetails) throws OAuthSystemException {
42 |
43 | //validate grant_type
44 | final String grantType = grantType();
45 | if (!clientDetails.grantTypes().contains(grantType)) {
46 | LOG.debug("Invalid grant_type '{}', client_id = '{}'", grantType, clientDetails.clientId());
47 | return invalidGrantTypeResponse(grantType);
48 | }
49 |
50 | //validate client_secret
51 | final String clientSecret = oauthRequest.getClientSecret();
52 | if (clientSecret == null || !clientSecret.equals(clientDetails.clientSecret())) {
53 | LOG.debug("Invalid client_secret '{}', client_id = '{}'", clientSecret, clientDetails.clientId());
54 | return invalidClientSecretResponse();
55 | }
56 |
57 | //validate scope
58 | final Set scopes = oauthRequest.getScopes();
59 | if (scopes.isEmpty() || excludeScopes(scopes, clientDetails)) {
60 | return invalidScopeResponse();
61 | }
62 |
63 | return null;
64 | }
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/OAuthHandler.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.oauth;
2 |
3 | import com.monkeyk.os.domain.oauth.AccessToken;
4 | import com.monkeyk.os.domain.oauth.ClientDetails;
5 | import com.monkeyk.os.domain.shared.BeanProvider;
6 | import com.monkeyk.os.service.OauthService;
7 | import org.apache.commons.lang.StringUtils;
8 | import org.apache.oltu.oauth2.as.response.OAuthASResponse;
9 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
10 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import javax.servlet.http.HttpServletResponse;
15 |
16 | /**
17 | * 2015/7/3
18 | *
19 | * @author Shengzhao Li
20 | */
21 | public abstract class OAuthHandler {
22 |
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(OAuthHandler.class);
25 |
26 | protected transient OauthService oauthService = BeanProvider.getBean(OauthService.class);
27 |
28 |
29 | private ClientDetails clientDetails;
30 |
31 |
32 | protected ClientDetails clientDetails() {
33 | if (clientDetails == null) {
34 | final String clientId = clientId();
35 | clientDetails = oauthService.loadClientDetails(clientId);
36 | LOG.debug("Load ClientDetails: {} by clientId: {}", clientDetails, clientId);
37 | }
38 | return clientDetails;
39 | }
40 |
41 |
42 | /**
43 | * Create AccessToken response
44 | *
45 | * @param accessToken AccessToken
46 | * @param queryOrJson True is QueryMessage, false is JSON message
47 | * @return OAuthResponse
48 | * @throws org.apache.oltu.oauth2.common.exception.OAuthSystemException
49 | */
50 | protected OAuthResponse createTokenResponse(AccessToken accessToken, boolean queryOrJson) throws OAuthSystemException {
51 | final ClientDetails clientDetails = clientDetails();
52 |
53 | final OAuthASResponse.OAuthTokenResponseBuilder builder = OAuthASResponse
54 | .tokenResponse(HttpServletResponse.SC_OK)
55 | .location(clientDetails.redirectUri())
56 | .setAccessToken(accessToken.tokenId())
57 | .setExpiresIn(String.valueOf(accessToken.currentTokenExpiredSeconds()))
58 | .setTokenType(accessToken.tokenType());
59 |
60 | final String refreshToken = accessToken.refreshToken();
61 | if (StringUtils.isNotEmpty(refreshToken)) {
62 | builder.setRefreshToken(refreshToken);
63 | }
64 |
65 | return queryOrJson ? builder.buildQueryMessage() : builder.buildJSONMessage();
66 | }
67 |
68 |
69 | protected abstract String clientId();
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/NewAccessTokenRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.utils.OAuthUtils;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/10/26
25 | *
26 | * Always return new AccessToken, exclude refreshToken
27 | *
28 | * @author Shengzhao Li
29 | */
30 | public class NewAccessTokenRetriever extends AbstractAccessTokenHandler {
31 |
32 |
33 | private static final Logger LOG = LoggerFactory.getLogger(NewAccessTokenRetriever.class);
34 |
35 |
36 | private final ClientDetails clientDetails;
37 | private final Set scopes;
38 |
39 | public NewAccessTokenRetriever(ClientDetails clientDetails, Set scopes) {
40 | this.clientDetails = clientDetails;
41 | this.scopes = scopes;
42 | }
43 |
44 | //Always return new AccessToken, exclude refreshToken
45 | public AccessToken retrieve() throws OAuthSystemException {
46 |
47 | String scopeAsText = getScope();
48 | final String username = currentUsername();
49 | final String clientId = clientDetails.clientId();
50 |
51 | final String authenticationId = authenticationIdGenerator.generate(clientId, username, scopeAsText);
52 |
53 | AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
54 | if (accessToken != null) {
55 | LOG.debug("Delete existed AccessToken: {}", accessToken);
56 | oauthRepository.deleteAccessToken(accessToken);
57 | }
58 | accessToken = createAndSaveAccessToken(clientDetails, false, username, authenticationId);
59 | LOG.debug("Create a new AccessToken: {}", accessToken);
60 |
61 | return accessToken;
62 | }
63 |
64 | private String getScope() {
65 | if (scopes != null) {
66 | return OAuthUtils.encodeScopes(scopes);
67 | } else {
68 | return null;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/AccessTokenByRefreshTokenChanger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 |
20 | /**
21 | * 2015/10/26
22 | *
23 | * @author Shengzhao Li
24 | */
25 | public class AccessTokenByRefreshTokenChanger extends AbstractAccessTokenHandler {
26 |
27 |
28 | private static final Logger LOG = LoggerFactory.getLogger(AccessTokenByRefreshTokenChanger.class);
29 |
30 |
31 | private final String refreshToken;
32 | private final String clientId;
33 |
34 | public AccessTokenByRefreshTokenChanger(String refreshToken, String clientId) {
35 | this.refreshToken = refreshToken;
36 | this.clientId = clientId;
37 | }
38 |
39 | /**
40 | * Get AccessToken
41 | * Generate a new AccessToken from existed(exclude token,refresh_token)
42 | * Update access_token,refresh_token, expired.
43 | * Save and remove old
44 | */
45 | public AccessToken change() throws OAuthSystemException {
46 |
47 | final AccessToken oldToken = oauthRepository.findAccessTokenByRefreshToken(refreshToken, clientId);
48 |
49 | AccessToken newAccessToken = oldToken.cloneMe();
50 | LOG.debug("Create new AccessToken: {} from old AccessToken: {}", newAccessToken, oldToken);
51 |
52 | ClientDetails details = oauthRepository.findClientDetails(clientId);
53 | newAccessToken.updateByClientDetails(details);
54 |
55 | final String authId = authenticationIdGenerator.generate(clientId, oldToken.username(), null);
56 | newAccessToken.authenticationId(authId)
57 | .tokenId(oAuthIssuer.accessToken())
58 | .refreshToken(oAuthIssuer.refreshToken());
59 |
60 | oauthRepository.deleteAccessToken(oldToken);
61 | LOG.debug("Delete old AccessToken: {}", oldToken);
62 |
63 | oauthRepository.saveAccessToken(newAccessToken);
64 | LOG.debug("Save new AccessToken: {}", newAccessToken);
65 |
66 | return newAccessToken;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/validator/CodeClientDetailsValidator.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.oauth.validator;
2 |
3 | import com.monkeyk.os.domain.oauth.ClientDetails;
4 | import org.apache.commons.lang.StringUtils;
5 | import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
6 | import org.apache.oltu.oauth2.common.error.OAuthError;
7 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
8 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import javax.servlet.http.HttpServletResponse;
13 | import java.util.Set;
14 |
15 | /**
16 | * 15-6-13
17 | *
18 | * @author Shengzhao Li
19 | */
20 | public class CodeClientDetailsValidator extends AbstractClientDetailsValidator {
21 |
22 | private static final Logger LOG = LoggerFactory.getLogger(CodeClientDetailsValidator.class);
23 |
24 | public CodeClientDetailsValidator(OAuthAuthzRequest oauthRequest) {
25 | super(oauthRequest);
26 | }
27 |
28 | /*
29 | * grant_type="authorization_code"
30 | * ?response_type=code&scope=read,write&client_id=[client_id]&redirect_uri=[redirect_uri]&state=[state]
31 | * */
32 | @Override
33 | public OAuthResponse validateSelf(ClientDetails clientDetails) throws OAuthSystemException {
34 | //validate redirect_uri
35 | final String redirectURI = oauthRequest.getRedirectURI();
36 | if (redirectURI == null || !redirectURI.equals(clientDetails.redirectUri())) {
37 | LOG.debug("Invalid redirect_uri '{}' by response_type = 'code', client_id = '{}'", redirectURI, clientDetails.clientId());
38 | return invalidRedirectUriResponse();
39 | }
40 |
41 | //validate scope
42 | final Set scopes = oauthRequest.getScopes();
43 | if (scopes.isEmpty() || excludeScopes(scopes, clientDetails)) {
44 | return invalidScopeResponse();
45 | }
46 |
47 | //validate state
48 | final String state = getState();
49 | if (StringUtils.isEmpty(state)) {
50 | LOG.debug("Invalid 'state', it is required, but it is empty");
51 | return invalidStateResponse();
52 | }
53 |
54 | return null;
55 | }
56 |
57 | private String getState() {
58 | return ((OAuthAuthzRequest) oauthRequest).getState();
59 | }
60 |
61 | private OAuthResponse invalidStateResponse() throws OAuthSystemException {
62 | return OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
63 | .setError(OAuthError.CodeResponse.INVALID_REQUEST)
64 | .setErrorDescription("Parameter 'state' is required")
65 | .buildJSONMessage();
66 | }
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/authz/src/test/java/com/monkeyk/os/web/ShiroTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.web;
13 |
14 | import org.apache.shiro.SecurityUtils;
15 | import org.apache.shiro.authc.UsernamePasswordToken;
16 | import org.apache.shiro.crypto.hash.Md5Hash;
17 | import org.apache.shiro.mgt.DefaultSecurityManager;
18 | import org.apache.shiro.mgt.SecurityManager;
19 | import org.apache.shiro.realm.Realm;
20 | import org.apache.shiro.realm.SimpleAccountRealm;
21 | import org.apache.shiro.subject.Subject;
22 | import org.testng.annotations.Test;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | import static org.testng.Assert.assertFalse;
28 | import static org.testng.Assert.assertTrue;
29 |
30 | /**
31 | * 15-6-10
32 | *
33 | * @author Shengzhao Li
34 | */
35 | public class ShiroTest {
36 |
37 |
38 | @Test
39 | public void login() {
40 | String username = "abc";
41 | //init SecurityManager
42 | SimpleAccountRealm realm = new SimpleAccountRealm("simple-realm");
43 | realm.addAccount(username, "abc", "USER");
44 |
45 | SimpleAccountRealm realm2 = new SimpleAccountRealm("simple-realm2");
46 | realm2.addAccount(username, "abc", "USER", "ADMIN");
47 |
48 | List realmList = new ArrayList<>();
49 | realmList.add(realm);
50 | realmList.add(realm2);
51 |
52 | SecurityManager securityManager = new DefaultSecurityManager(realmList);
53 | SecurityUtils.setSecurityManager(securityManager);
54 |
55 | UsernamePasswordToken token = new UsernamePasswordToken(username, "abcdd");
56 |
57 | final Subject subject = SecurityUtils.getSubject();
58 | subject.login(token);
59 |
60 |
61 | final Subject subject1 = SecurityUtils.getSubject();
62 | assertTrue(subject1.isAuthenticated());
63 |
64 | assertFalse(subject1.isPermitted("OK"));
65 | assertTrue(subject1.hasRole("USER"));
66 |
67 | // assertTrue(subject1.isPermitted("USER:c,u"));
68 |
69 |
70 | }
71 |
72 |
73 | @Test
74 | public void md5() {
75 |
76 | Md5Hash md5Hash = new Md5Hash("admin");
77 | System.out.println(md5Hash.toString());
78 | System.out.println(md5Hash.toHex());
79 | System.out.println(md5Hash.toBase64());
80 |
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/resources/src/test/java/com/monkeyk/os/web/ShiroTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.web;
13 |
14 | import org.apache.shiro.SecurityUtils;
15 | import org.apache.shiro.authc.UsernamePasswordToken;
16 | import org.apache.shiro.crypto.hash.Md5Hash;
17 | import org.apache.shiro.mgt.DefaultSecurityManager;
18 | import org.apache.shiro.mgt.SecurityManager;
19 | import org.apache.shiro.realm.Realm;
20 | import org.apache.shiro.realm.SimpleAccountRealm;
21 | import org.apache.shiro.subject.Subject;
22 | import org.testng.annotations.Test;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | import static org.testng.Assert.assertFalse;
28 | import static org.testng.Assert.assertTrue;
29 |
30 | /**
31 | * 15-6-10
32 | *
33 | * @author Shengzhao Li
34 | */
35 | public class ShiroTest {
36 |
37 |
38 | @Test
39 | public void login() {
40 | String username = "abc";
41 | //init SecurityManager
42 | SimpleAccountRealm realm = new SimpleAccountRealm("simple-realm");
43 | realm.addAccount(username, "abc", "USER");
44 |
45 | SimpleAccountRealm realm2 = new SimpleAccountRealm("simple-realm2");
46 | realm2.addAccount(username, "abc", "USER", "ADMIN");
47 |
48 | List realmList = new ArrayList<>();
49 | realmList.add(realm);
50 | realmList.add(realm2);
51 |
52 | SecurityManager securityManager = new DefaultSecurityManager(realmList);
53 | SecurityUtils.setSecurityManager(securityManager);
54 |
55 | UsernamePasswordToken token = new UsernamePasswordToken(username, "abcdd");
56 |
57 | final Subject subject = SecurityUtils.getSubject();
58 | subject.login(token);
59 |
60 |
61 | final Subject subject1 = SecurityUtils.getSubject();
62 | assertTrue(subject1.isAuthenticated());
63 |
64 | assertFalse(subject1.isPermitted("OK"));
65 | assertTrue(subject1.hasRole("USER"));
66 |
67 | // assertTrue(subject1.isPermitted("USER:c,u"));
68 |
69 |
70 | }
71 |
72 |
73 | @Test
74 | public void md5() {
75 |
76 | Md5Hash md5Hash = new Md5Hash("admin");
77 | System.out.println(md5Hash.toString());
78 | System.out.println(md5Hash.toHex());
79 | System.out.println(md5Hash.toBase64());
80 |
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/validator/PasswordClientDetailsValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.validator;
13 |
14 | import com.monkeyk.os.domain.oauth.ClientDetails;
15 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/7/5
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class PasswordClientDetailsValidator extends AbstractOauthTokenValidator {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(PasswordClientDetailsValidator.class);
31 |
32 |
33 | public PasswordClientDetailsValidator(OAuthTokenxRequest oauthRequest) {
34 | super(oauthRequest);
35 | }
36 |
37 | /*
38 | * /oauth/token?client_id=mobile-client&client_secret=mobile&grant_type=password&scope=read,write&username=mobile&password=mobile
39 | * */
40 | @Override
41 | protected OAuthResponse validateSelf(ClientDetails clientDetails) throws OAuthSystemException {
42 |
43 | //validate grant_type
44 | final String grantType = grantType();
45 | if (!clientDetails.grantTypes().contains(grantType)) {
46 | LOG.debug("Invalid grant_type '{}', client_id = '{}'", grantType, clientDetails.clientId());
47 | return invalidGrantTypeResponse(grantType);
48 | }
49 |
50 | //validate client_secret
51 | final String clientSecret = oauthRequest.getClientSecret();
52 | if (clientSecret == null || !clientSecret.equals(clientDetails.clientSecret())) {
53 | LOG.debug("Invalid client_secret '{}', client_id = '{}'", clientSecret, clientDetails.clientId());
54 | return invalidClientSecretResponse();
55 | }
56 |
57 | //validate scope
58 | final Set scopes = oauthRequest.getScopes();
59 | if (scopes.isEmpty() || excludeScopes(scopes, clientDetails)) {
60 | return invalidScopeResponse();
61 | }
62 |
63 | //validate username,password
64 | if (invalidUsernamePassword()) {
65 | return invalidUsernamePasswordResponse();
66 | }
67 |
68 |
69 | return null;
70 | }
71 |
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/RefreshTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
16 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
17 | import com.monkeyk.os.oauth.validator.RefreshTokenClientDetailsValidator;
18 | import com.monkeyk.os.web.WebUtils;
19 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
20 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
21 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
22 | import org.apache.oltu.oauth2.common.message.types.GrantType;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | /**
27 | * 2015/7/3
28 | *
29 | * grant_type=refresh_token
30 | *
31 | * @author Shengzhao Li
32 | */
33 | public class RefreshTokenHandler extends AbstractOAuthTokenHandler {
34 |
35 | private static final Logger LOG = LoggerFactory.getLogger(RefreshTokenHandler.class);
36 |
37 |
38 | @Override
39 | public boolean support(OAuthTokenxRequest tokenRequest) throws OAuthProblemException {
40 | final String grantType = tokenRequest.getGrantType();
41 | return GrantType.REFRESH_TOKEN.toString().equalsIgnoreCase(grantType);
42 | }
43 |
44 | /**
45 | * URL demo:
46 | * /oauth/token?client_id=mobile-client&client_secret=mobile&grant_type=refresh_token&refresh_token=b36f4978-a172-4aa8-af89-60f58abe3ba1
47 | *
48 | * @throws org.apache.oltu.oauth2.common.exception.OAuthProblemException
49 | */
50 | @Override
51 | public void handleAfterValidation() throws OAuthProblemException, OAuthSystemException {
52 |
53 | final String refreshToken = tokenRequest.getRefreshToken();
54 | AccessToken accessToken = oauthService.changeAccessTokenByRefreshToken(refreshToken, tokenRequest.getClientId());
55 |
56 | final OAuthResponse tokenResponse = createTokenResponse(accessToken, false);
57 |
58 | LOG.debug("'refresh_token' response: {}", tokenResponse);
59 | WebUtils.writeOAuthJsonResponse(response, tokenResponse);
60 |
61 | }
62 |
63 | @Override
64 | protected AbstractClientDetailsValidator getValidator() {
65 | return new RefreshTokenClientDetailsValidator(tokenRequest);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/authz/src/main/resources/spring/authz-security.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | /favicon.ico = anon
46 | /resources/** = anon
47 | /login = anon
48 | /unauthorized = anon
49 | # OAuth anon
50 | /oauth/** = anon
51 | /logout = logout
52 | # admin role
53 | /admin/** = authc, roles["Admin"]
54 | #user permissions
55 | /user/list = authc, perms["user:list"]
56 | /user/create = authc, perms["user:create"]
57 | # everything else requires authentication:
58 | /** = authc
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/validator/AbstractOauthTokenValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.validator;
13 |
14 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
15 | import org.apache.oltu.oauth2.common.error.OAuthError;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
18 | import org.apache.shiro.SecurityUtils;
19 | import org.apache.shiro.authc.UsernamePasswordToken;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 |
23 | import javax.servlet.http.HttpServletResponse;
24 |
25 | /**
26 | * 2015/7/4
27 | *
28 | * @author Shengzhao Li
29 | */
30 | public abstract class AbstractOauthTokenValidator extends AbstractClientDetailsValidator {
31 |
32 | private static final Logger LOG = LoggerFactory.getLogger(AbstractOauthTokenValidator.class);
33 |
34 |
35 | protected OAuthTokenxRequest tokenRequest;
36 |
37 | protected AbstractOauthTokenValidator(OAuthTokenxRequest tokenRequest) {
38 | super(tokenRequest);
39 | this.tokenRequest = tokenRequest;
40 | }
41 |
42 |
43 | protected String grantType() {
44 | return tokenRequest.getGrantType();
45 | }
46 |
47 |
48 | protected OAuthResponse invalidGrantTypeResponse(String grantType) throws OAuthSystemException {
49 | return OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
50 | .setError(OAuthError.TokenResponse.INVALID_GRANT)
51 | .setErrorDescription("Invalid grant_type '" + grantType + "'")
52 | .buildJSONMessage();
53 | }
54 |
55 |
56 | //true is invalided
57 | protected boolean invalidUsernamePassword() {
58 | final String username = tokenRequest.getUsername();
59 | final String password = tokenRequest.getPassword();
60 | try {
61 | SecurityUtils.getSubject().login(new UsernamePasswordToken(username, password));
62 | } catch (Exception e) {
63 | LOG.debug("Login failed by username: " + username, e);
64 | return true;
65 | }
66 | return false;
67 | }
68 |
69 | protected OAuthResponse invalidUsernamePasswordResponse() throws OAuthSystemException {
70 | return OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
71 | .setError(OAuthError.TokenResponse.INVALID_GRANT)
72 | .setErrorDescription("Bad credentials")
73 | .buildJSONMessage();
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/ClientCredentialsTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
16 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
17 | import com.monkeyk.os.oauth.validator.ClientCredentialsClientDetailsValidator;
18 | import com.monkeyk.os.web.WebUtils;
19 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
20 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
21 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
22 | import org.apache.oltu.oauth2.common.message.types.GrantType;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | /**
27 | * 2015/7/3
28 | *
29 | * grant_type=client_credentials
30 | *
31 | * @author Shengzhao Li
32 | */
33 | public class ClientCredentialsTokenHandler extends AbstractOAuthTokenHandler {
34 |
35 | private static final Logger LOG = LoggerFactory.getLogger(ClientCredentialsTokenHandler.class);
36 |
37 |
38 | @Override
39 | public boolean support(OAuthTokenxRequest tokenRequest) throws OAuthProblemException {
40 | final String grantType = tokenRequest.getGrantType();
41 | return GrantType.CLIENT_CREDENTIALS.toString().equalsIgnoreCase(grantType);
42 | }
43 |
44 | /**
45 | * /oauth/token?client_id=credentials-client&client_secret=credentials-secret&grant_type=client_credentials&scope=read write
46 | *
47 | * Response access_token
48 | * If exist AccessToken and it is not expired, return it
49 | * otherwise, return a new AccessToken
50 | *
51 | * {"access_token":"38187f32-e4fb-4650-8e4a-99903b66f20e","token_type":"bearer","expires_in":7}
52 | */
53 | @Override
54 | public void handleAfterValidation() throws OAuthProblemException, OAuthSystemException {
55 |
56 | AccessToken accessToken = oauthService.retrieveClientCredentialsAccessToken(clientDetails(),
57 | tokenRequest.getScopes());
58 | final OAuthResponse tokenResponse = createTokenResponse(accessToken, false);
59 |
60 | LOG.debug("'client_credentials' response: {}", tokenResponse);
61 | WebUtils.writeOAuthJsonResponse(response, tokenResponse);
62 |
63 |
64 | }
65 |
66 | @Override
67 | protected AbstractClientDetailsValidator getValidator() {
68 | return new ClientCredentialsClientDetailsValidator(tokenRequest);
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/PasswordTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
16 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
17 | import com.monkeyk.os.oauth.validator.PasswordClientDetailsValidator;
18 | import com.monkeyk.os.web.WebUtils;
19 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
20 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
21 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
22 | import org.apache.oltu.oauth2.common.message.types.GrantType;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | /**
27 | * 2015/7/3
28 | *
29 | * grant_type=password
30 | *
31 | * @author Shengzhao Li
32 | */
33 | public class PasswordTokenHandler extends AbstractOAuthTokenHandler {
34 |
35 | private static final Logger LOG = LoggerFactory.getLogger(PasswordTokenHandler.class);
36 |
37 |
38 | @Override
39 | public boolean support(OAuthTokenxRequest tokenRequest) throws OAuthProblemException {
40 | final String grantType = tokenRequest.getGrantType();
41 | return GrantType.PASSWORD.toString().equalsIgnoreCase(grantType);
42 | }
43 |
44 | @Override
45 | protected AbstractClientDetailsValidator getValidator() {
46 | return new PasswordClientDetailsValidator(tokenRequest);
47 | }
48 |
49 | /**
50 | * /oauth/token?client_id=mobile-client&client_secret=mobile&grant_type=password&scope=read,write&username=mobile&password=mobile
51 | *
52 | * Response access_token
53 | * If exist AccessToken and it is not expired, return it
54 | * otherwise, return a new AccessToken(include refresh_token)
55 | *
56 | * {"token_type":"Bearer","expires_in":33090,"refresh_token":"976aeaf7df1ee998f98f15acd1de63ea","access_token":"7811aff100eb7dadec132f45f1c01727"}
57 | */
58 | @Override
59 | public void handleAfterValidation() throws OAuthProblemException, OAuthSystemException {
60 |
61 | AccessToken accessToken = oauthService.retrievePasswordAccessToken(clientDetails(),
62 | tokenRequest.getScopes(), tokenRequest.getUsername());
63 | final OAuthResponse tokenResponse = createTokenResponse(accessToken, false);
64 |
65 | LOG.debug("'password' response: {}", tokenResponse);
66 | WebUtils.writeOAuthJsonResponse(response, tokenResponse);
67 |
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/web/WebUtils.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 | import org.apache.oltu.oauth2.common.OAuth;
5 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 | import java.io.PrintWriter;
11 | import java.util.Map;
12 |
13 | /**
14 | * @author Shengzhao Li
15 | */
16 | public abstract class WebUtils {
17 |
18 |
19 | private WebUtils() {
20 | }
21 |
22 |
23 | public static void writeOAuthJsonResponse(HttpServletResponse response, OAuthResponse oAuthResponse) {
24 |
25 | final int responseStatus = oAuthResponse.getResponseStatus();
26 | try {
27 |
28 | final Map headers = oAuthResponse.getHeaders();
29 | for (String key : headers.keySet()) {
30 | response.addHeader(key, headers.get(key));
31 | }
32 | // CORS setting
33 | response.setHeader("Access-Control-Allow-Origin", "*");
34 |
35 | response.setContentType(OAuth.ContentType.JSON); //json
36 | response.setStatus(responseStatus);
37 |
38 | final PrintWriter out = response.getWriter();
39 | out.print(oAuthResponse.getBody());
40 | out.flush();
41 | } catch (IOException e) {
42 | throw new IllegalStateException("Write OAuthResponse error", e);
43 | }
44 | }
45 |
46 |
47 | public static void writeOAuthQueryResponse(HttpServletResponse response, OAuthResponse oAuthResponse) {
48 | final String locationUri = oAuthResponse.getLocationUri();
49 | try {
50 |
51 | final Map headers = oAuthResponse.getHeaders();
52 | for (String key : headers.keySet()) {
53 | response.addHeader(key, headers.get(key));
54 | }
55 |
56 | response.setStatus(oAuthResponse.getResponseStatus());
57 | response.sendRedirect(locationUri);
58 |
59 | } catch (IOException e) {
60 | throw new IllegalStateException("Write OAuthResponse error", e);
61 | }
62 | }
63 |
64 |
65 | /**
66 | * Retrieve client ip address
67 | *
68 | * @param request HttpServletRequest
69 | * @return IP
70 | */
71 | public static String retrieveClientIp(HttpServletRequest request) {
72 | String ip = request.getHeader("x-forwarded-for");
73 | if (isUnAvailableIp(ip)) {
74 | ip = request.getHeader("Proxy-Client-IP");
75 | }
76 | if (isUnAvailableIp(ip)) {
77 | ip = request.getHeader("WL-Proxy-Client-IP");
78 | }
79 | if (isUnAvailableIp(ip)) {
80 | ip = request.getRemoteAddr();
81 | }
82 | return ip;
83 | }
84 |
85 | private static boolean isUnAvailableIp(String ip) {
86 | return (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip));
87 | }
88 | }
--------------------------------------------------------------------------------
/resources/src/main/java/com/monkeyk/os/web/WebUtils.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.web;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 | import org.apache.oltu.oauth2.common.OAuth;
5 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.io.IOException;
10 | import java.io.PrintWriter;
11 | import java.util.Map;
12 |
13 | /**
14 | * @author Shengzhao Li
15 | */
16 | public abstract class WebUtils {
17 |
18 |
19 | private WebUtils() {
20 | }
21 |
22 |
23 | public static void writeOAuthJsonResponse(HttpServletResponse response, OAuthResponse oAuthResponse) {
24 |
25 | final int responseStatus = oAuthResponse.getResponseStatus();
26 | try {
27 |
28 | final Map headers = oAuthResponse.getHeaders();
29 | for (String key : headers.keySet()) {
30 | response.addHeader(key, headers.get(key));
31 | }
32 | // CORS setting
33 | response.setHeader("Access-Control-Allow-Origin", "*");
34 |
35 | response.setContentType(OAuth.ContentType.JSON); //json
36 | response.setStatus(responseStatus);
37 |
38 | final PrintWriter out = response.getWriter();
39 | out.print(oAuthResponse.getBody());
40 | out.flush();
41 | } catch (IOException e) {
42 | throw new IllegalStateException("Write OAuthResponse error", e);
43 | }
44 | }
45 |
46 |
47 | public static void writeOAuthQueryResponse(HttpServletResponse response, OAuthResponse oAuthResponse) {
48 | final String locationUri = oAuthResponse.getLocationUri();
49 | try {
50 |
51 | final Map headers = oAuthResponse.getHeaders();
52 | for (String key : headers.keySet()) {
53 | response.addHeader(key, headers.get(key));
54 | }
55 |
56 | response.setStatus(oAuthResponse.getResponseStatus());
57 | response.sendRedirect(locationUri);
58 |
59 | } catch (IOException e) {
60 | throw new IllegalStateException("Write OAuthResponse error", e);
61 | }
62 | }
63 |
64 |
65 | /**
66 | * Retrieve client ip address
67 | *
68 | * @param request HttpServletRequest
69 | * @return IP
70 | */
71 | public static String retrieveClientIp(HttpServletRequest request) {
72 | String ip = request.getHeader("x-forwarded-for");
73 | if (isUnAvailableIp(ip)) {
74 | ip = request.getHeader("Proxy-Client-IP");
75 | }
76 | if (isUnAvailableIp(ip)) {
77 | ip = request.getHeader("WL-Proxy-Client-IP");
78 | }
79 | if (isUnAvailableIp(ip)) {
80 | ip = request.getRemoteAddr();
81 | }
82 | return ip;
83 | }
84 |
85 | private static boolean isUnAvailableIp(String ip) {
86 | return (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip));
87 | }
88 | }
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/AbstractOAuthTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.web.WebUtils;
15 | import com.monkeyk.os.oauth.OAuthHandler;
16 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
17 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
18 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
19 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
20 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import javax.servlet.http.HttpServletResponse;
25 |
26 | /**
27 | * 2015/7/3
28 | *
29 | * @author Shengzhao Li
30 | */
31 | public abstract class AbstractOAuthTokenHandler extends OAuthHandler implements OAuthTokenHandler {
32 |
33 | private static final Logger LOG = LoggerFactory.getLogger(AbstractOAuthTokenHandler.class);
34 |
35 |
36 | protected OAuthTokenxRequest tokenRequest;
37 | protected HttpServletResponse response;
38 |
39 | @Override
40 | public final void handle(OAuthTokenxRequest tokenRequest, HttpServletResponse response) throws OAuthProblemException, OAuthSystemException {
41 | this.tokenRequest = tokenRequest;
42 | this.response = response;
43 |
44 | //validate
45 | if (validateFailed()) {
46 | return;
47 | }
48 |
49 |
50 | handleAfterValidation();
51 | }
52 |
53 |
54 | protected boolean validateFailed() throws OAuthSystemException {
55 | AbstractClientDetailsValidator validator = getValidator();
56 | LOG.debug("Use [{}] validate client: {}", validator, tokenRequest.getClientId());
57 |
58 | final OAuthResponse oAuthResponse = validator.validate();
59 | return checkAndResponseValidateFailed(oAuthResponse);
60 | }
61 |
62 | protected boolean checkAndResponseValidateFailed(OAuthResponse oAuthResponse) {
63 | if (oAuthResponse != null) {
64 | LOG.debug("Validate OAuthAuthzRequest(client_id={}) failed", tokenRequest.getClientId());
65 | WebUtils.writeOAuthJsonResponse(response, oAuthResponse);
66 | return true;
67 | }
68 | return false;
69 | }
70 |
71 | protected abstract AbstractClientDetailsValidator getValidator();
72 |
73 |
74 | protected String clientId() {
75 | return tokenRequest.getClientId();
76 | }
77 |
78 | protected abstract void handleAfterValidation() throws OAuthProblemException, OAuthSystemException;
79 |
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/ClientCredentialsAccessTokenRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.utils.OAuthUtils;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/10/26
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class ClientCredentialsAccessTokenRetriever extends AbstractAccessTokenHandler {
29 |
30 | private static final Logger LOG = LoggerFactory.getLogger(ClientCredentialsAccessTokenRetriever.class);
31 |
32 |
33 | private final ClientDetails clientDetails;
34 | private final Set scopes;
35 |
36 | public ClientCredentialsAccessTokenRetriever(ClientDetails clientDetails, Set scopes) {
37 | this.clientDetails = clientDetails;
38 | this.scopes = scopes;
39 | }
40 |
41 |
42 | public AccessToken retrieve() throws OAuthSystemException {
43 |
44 | String scope = OAuthUtils.encodeScopes(scopes);
45 | final String clientId = clientDetails.clientId();
46 | //username = clientId
47 |
48 | final String authenticationId = authenticationIdGenerator.generate(clientId, clientId, scope);
49 | AccessToken accessToken = oauthRepository.findAccessToken(clientId, clientId, authenticationId);
50 |
51 | boolean needCreated = needCreated(clientId, accessToken);
52 |
53 | if (needCreated) {
54 | //Ignore refresh_token
55 | accessToken = createAndSaveAccessToken(clientDetails, false, clientId, authenticationId);
56 | LOG.debug("Create a new AccessToken: {}", accessToken);
57 | }
58 |
59 | return accessToken;
60 | }
61 |
62 | private boolean needCreated(String clientId, AccessToken accessToken) {
63 | boolean needCreate = false;
64 | if (accessToken == null) {
65 | needCreate = true;
66 | LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
67 | } else if (accessToken.tokenExpired()) {
68 | LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
69 | oauthRepository.deleteAccessToken(accessToken);
70 | needCreate = true;
71 | } else {
72 | LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
73 | }
74 | return needCreate;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/oauth/token/AuthorizationCodeTokenHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Andaily Information Technology Co. Ltd
3 | * www.andaily.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * Andaily Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with Andaily Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.oauth.token;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.web.WebUtils;
16 | import com.monkeyk.os.oauth.OAuthTokenxRequest;
17 | import com.monkeyk.os.oauth.validator.AbstractClientDetailsValidator;
18 | import com.monkeyk.os.oauth.validator.AuthorizationCodeClientDetailsValidator;
19 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
20 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
21 | import org.apache.oltu.oauth2.common.message.OAuthResponse;
22 | import org.apache.oltu.oauth2.common.message.types.GrantType;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | /**
27 | * 2015/7/3
28 | *
29 | * grant_type=authorization_code
30 | *
31 | * @author Shengzhao Li
32 | */
33 | public class AuthorizationCodeTokenHandler extends AbstractOAuthTokenHandler {
34 |
35 | private static final Logger LOG = LoggerFactory.getLogger(AuthorizationCodeTokenHandler.class);
36 |
37 | @Override
38 | public boolean support(OAuthTokenxRequest tokenRequest) throws OAuthProblemException {
39 | final String grantType = tokenRequest.getGrantType();
40 | return GrantType.AUTHORIZATION_CODE.toString().equalsIgnoreCase(grantType);
41 | }
42 |
43 | /*
44 | *
45 | * /oauth/token?client_id=unity-client&client_secret=unity&grant_type=authorization_code&code=zLl170&redirect_uri=redirect_uri
46 | * */
47 | @Override
48 | public void handleAfterValidation() throws OAuthProblemException, OAuthSystemException {
49 |
50 | //response token, always new
51 | responseToken();
52 |
53 | //remove code lastly
54 | removeCode();
55 | }
56 |
57 | private void removeCode() {
58 | final String code = tokenRequest.getCode();
59 | final boolean result = oauthService.removeOauthCode(code, clientDetails());
60 | LOG.debug("Remove code: {} result: {}", code, result);
61 | }
62 |
63 | private void responseToken() throws OAuthSystemException {
64 | AccessToken accessToken = oauthService.retrieveAuthorizationCodeAccessToken(clientDetails(), tokenRequest.getCode());
65 | final OAuthResponse tokenResponse = createTokenResponse(accessToken, false);
66 |
67 | LOG.debug("'authorization_code' response: {}", tokenResponse);
68 | WebUtils.writeOAuthJsonResponse(response, tokenResponse);
69 | }
70 |
71 | @Override
72 | protected AbstractClientDetailsValidator getValidator() {
73 | return new AuthorizationCodeClientDetailsValidator(tokenRequest);
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/infrastructure/UsersRedisRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.infrastructure;
13 |
14 | import com.monkeyk.os.domain.users.Roles;
15 | import com.monkeyk.os.domain.users.Users;
16 | import com.monkeyk.os.domain.users.UsersRepository;
17 | import com.monkeyk.os.infrastructure.cache.AbstractCacheSupport;
18 |
19 | import static com.monkeyk.os.infrastructure.cache.CacheKeyGenerator.*;
20 |
21 | import com.monkeyk.os.infrastructure.cache.CacheNames;
22 | import com.monkeyk.os.infrastructure.jdbc.UsersJdbcRepository;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 | import org.springframework.beans.factory.annotation.Autowired;
26 | import org.springframework.cache.Cache;
27 | import org.springframework.cache.CacheManager;
28 | import org.springframework.stereotype.Repository;
29 |
30 | import java.util.List;
31 |
32 | /**
33 | * 2015/10/26
34 | *
35 | * @author Shengzhao Li
36 | */
37 | @Repository("usersRedisRepository")
38 | public class UsersRedisRepository extends AbstractCacheSupport implements UsersRepository {
39 |
40 |
41 | private static final Logger LOG = LoggerFactory.getLogger(UsersRedisRepository.class);
42 |
43 | @Autowired
44 | private UsersJdbcRepository usersRepository;
45 |
46 | @Autowired
47 | private CacheManager cacheManager;
48 |
49 |
50 | @Override
51 | public Users findUsersByUsername(String username) {
52 |
53 | final Cache usersCache = getUsersCache();
54 |
55 | final String key = generateUsersKey(username);
56 | Users users = (Users) getFromCache(usersCache, key);
57 |
58 | if (users == null) {
59 | users = usersRepository.findUsersByUsername(username);
60 | putToCache(usersCache, key, users);
61 | LOG.debug("Load Users[{}] from DB and cache it, key = {}", users, key);
62 | }
63 |
64 | return users;
65 | }
66 |
67 | @Override
68 | public List findRolesByUsername(String username) {
69 |
70 | final Cache usersCache = getUsersCache();
71 |
72 | final String key = generateUserRolesKey(username);
73 | @SuppressWarnings("unchecked")
74 | List rolesList = (List) getFromCache(usersCache, key);
75 |
76 | if (rolesList == null) {
77 | rolesList = usersRepository.findRolesByUsername(username);
78 | putToCache(usersCache, key, rolesList);
79 | LOG.debug("Load User roles[{}] from DB and cache it, key = {}", rolesList, key);
80 | }
81 |
82 | return rolesList;
83 | }
84 |
85 |
86 | private Cache getUsersCache() {
87 | return cacheManager.getCache(CacheNames.USERS_CACHE);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/authz/src/main/java/com/monkeyk/os/service/business/PasswordAccessTokenRetriever.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.service.business;
13 |
14 | import com.monkeyk.os.domain.oauth.AccessToken;
15 | import com.monkeyk.os.domain.oauth.ClientDetails;
16 | import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
17 | import org.apache.oltu.oauth2.common.utils.OAuthUtils;
18 | import org.slf4j.Logger;
19 | import org.slf4j.LoggerFactory;
20 |
21 | import java.util.Set;
22 |
23 | /**
24 | * 2015/10/26
25 | *
26 | * @author Shengzhao Li
27 | */
28 | public class PasswordAccessTokenRetriever extends AbstractAccessTokenHandler {
29 |
30 |
31 | private static final Logger LOG = LoggerFactory.getLogger(PasswordAccessTokenRetriever.class);
32 |
33 |
34 | private final ClientDetails clientDetails;
35 | private final Set scopes;
36 | private final String username;
37 |
38 | public PasswordAccessTokenRetriever(ClientDetails clientDetails, Set scopes, String username) {
39 | this.clientDetails = clientDetails;
40 | this.scopes = scopes;
41 | this.username = username;
42 | }
43 |
44 | //grant_type=password AccessToken
45 | public AccessToken retrieve() throws OAuthSystemException {
46 |
47 | String scope = OAuthUtils.encodeScopes(scopes);
48 | final String clientId = clientDetails.clientId();
49 |
50 | final String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
51 | AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
52 |
53 | boolean needCreated = needCreated(clientId, accessToken);
54 |
55 | if (needCreated) {
56 | accessToken = createAndSaveAccessToken(clientDetails, clientDetails.supportRefreshToken(), username, authenticationId);
57 | LOG.debug("Create a new AccessToken: {}", accessToken);
58 | }
59 |
60 | return accessToken;
61 | }
62 |
63 | private boolean needCreated(String clientId, AccessToken accessToken) {
64 | boolean needCreate = false;
65 |
66 | if (accessToken == null) {
67 | needCreate = true;
68 | LOG.debug("Not found AccessToken from repository, will create a new one, client_id: {}", clientId);
69 | } else if (accessToken.tokenExpired()) {
70 | LOG.debug("Delete expired AccessToken: {} and create a new one, client_id: {}", accessToken, clientId);
71 | oauthRepository.deleteAccessToken(accessToken);
72 | needCreate = true;
73 | } else {
74 | LOG.debug("Use existed AccessToken: {}, client_id: {}", accessToken, clientId);
75 | }
76 | return needCreate;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/resources/src/main/java/com/monkeyk/os/oauth/resources/MkkOAuthRSProvider.java:
--------------------------------------------------------------------------------
1 | package com.monkeyk.os.oauth.resources;
2 |
3 | import com.monkeyk.os.domain.oauth.AccessToken;
4 | import com.monkeyk.os.domain.oauth.ClientDetails;
5 | import com.monkeyk.os.domain.rs.RSOAuthClient;
6 | import com.monkeyk.os.domain.shared.BeanProvider;
7 | import com.monkeyk.os.service.OAuthRSService;
8 | import org.apache.oltu.oauth2.common.error.OAuthError;
9 | import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
10 | import org.apache.oltu.oauth2.rsfilter.OAuthDecision;
11 | import org.apache.oltu.oauth2.rsfilter.OAuthRSProvider;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import javax.servlet.http.HttpServletRequest;
16 |
17 | /**
18 | * 2015/7/8
19 | *
20 | * @author Shengzhao Li
21 | */
22 | public class MkkOAuthRSProvider implements OAuthRSProvider {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(MkkOAuthRSProvider.class);
25 |
26 |
27 | private transient OAuthRSService rsService = BeanProvider.getBean(OAuthRSService.class);
28 |
29 | @Override
30 | public OAuthDecision validateRequest(String rsId, String token, HttpServletRequest req) throws OAuthProblemException {
31 | LOG.debug("Call OAuthRSProvider, rsId: {},token: {},req: {}", new Object[]{rsId, token, req});
32 |
33 | AccessToken accessToken = rsService.loadAccessTokenByTokenId(token);
34 | validateToken(token, accessToken);
35 |
36 | ClientDetails clientDetails = rsService.loadClientDetails(accessToken.clientId(), rsId);
37 | validateClientDetails(token, accessToken, clientDetails);
38 |
39 |
40 | //TODO: It is OK?
41 | MkkOAuthDecision oAuthDecision = new MkkOAuthDecision().setOAuthClient(new RSOAuthClient(clientDetails));
42 | oAuthDecision.setPrincipal(new MkkOAuthPrincipal(accessToken.username()));
43 | oAuthDecision.setAuthorized(true);
44 |
45 | return oAuthDecision;
46 | }
47 |
48 | private void validateClientDetails(String token, AccessToken accessToken, ClientDetails clientDetails) throws OAuthProblemException {
49 | if (clientDetails == null || clientDetails.archived()) {
50 | LOG.debug("Invalid ClientDetails: {} by client_id: {}, it is null or archived", clientDetails, accessToken.clientId());
51 | throw OAuthProblemException.error(OAuthError.ResourceResponse.INVALID_TOKEN)
52 | .description("Invalid client by token: " + token);
53 | }
54 | }
55 |
56 | private void validateToken(String token, AccessToken accessToken) throws OAuthProblemException {
57 | if (accessToken == null) {
58 | LOG.debug("Invalid access_token: {}, because it is null", token);
59 | throw OAuthProblemException.error(OAuthError.ResourceResponse.INVALID_TOKEN)
60 | .description("Invalid access_token: " + token);
61 | }
62 | if (accessToken.tokenExpired()) {
63 | LOG.debug("Invalid access_token: {}, because it is expired", token);
64 | throw OAuthProblemException.error(OAuthError.ResourceResponse.EXPIRED_TOKEN)
65 | .description("Expired access_token: " + token);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/resources/src/main/java/com/monkeyk/os/infrastructure/UsersRSRedisRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015 MONKEYK Information Technology Co. Ltd
3 | * www.monkeyk.com
4 | * All rights reserved.
5 | *
6 | * This software is the confidential and proprietary information of
7 | * MONKEYK Information Technology Co. Ltd ("Confidential Information").
8 | * You shall not disclose such Confidential Information and shall use
9 | * it only in accordance with the terms of the license agreement you
10 | * entered into with MONKEYK Information Technology Co. Ltd.
11 | */
12 | package com.monkeyk.os.infrastructure;
13 |
14 | import com.monkeyk.os.domain.users.Roles;
15 | import com.monkeyk.os.domain.users.Users;
16 | import com.monkeyk.os.domain.users.UsersRepository;
17 | import com.monkeyk.os.infrastructure.cache.AbstractCacheSupport;
18 | import com.monkeyk.os.infrastructure.cache.CacheNames;
19 | import com.monkeyk.os.infrastructure.jdbc.UsersRSJdbcRepository;
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.cache.Cache;
24 | import org.springframework.cache.CacheManager;
25 | import org.springframework.stereotype.Repository;
26 |
27 | import java.util.List;
28 |
29 | import static com.monkeyk.os.infrastructure.cache.CacheKeyGenerator.generateUserRolesKey;
30 | import static com.monkeyk.os.infrastructure.cache.CacheKeyGenerator.generateUsersKey;
31 |
32 | /**
33 | * 2015/10/27
34 | *
35 | * @author Shengzhao Li
36 | */
37 | @Repository("usersRSRedisRepository")
38 | public class UsersRSRedisRepository extends AbstractCacheSupport implements UsersRepository {
39 |
40 |
41 | private static final Logger LOG = LoggerFactory.getLogger(UsersRSRedisRepository.class);
42 |
43 | @Autowired
44 | private UsersRSJdbcRepository usersRepository;
45 |
46 | @Autowired
47 | private CacheManager cacheManager;
48 |
49 |
50 | @Override
51 | public Users findUsersByUsername(String username) {
52 |
53 | final Cache usersCache = getUsersCache();
54 |
55 | final String key = generateUsersKey(username);
56 | Users users = (Users) getFromCache(usersCache, key);
57 |
58 | if (users == null) {
59 | users = usersRepository.findUsersByUsername(username);
60 | putToCache(usersCache, key, users);
61 | LOG.debug("Load Users[{}] from DB and cache it, key = {}", users, key);
62 | }
63 |
64 | return users;
65 | }
66 |
67 | @Override
68 | public List findRolesByUsername(String username) {
69 |
70 | final Cache usersCache = getUsersCache();
71 |
72 | final String key = generateUserRolesKey(username);
73 | @SuppressWarnings("unchecked")
74 | List rolesList = (List) getFromCache(usersCache, key);
75 |
76 | if (rolesList == null) {
77 | rolesList = usersRepository.findRolesByUsername(username);
78 | putToCache(usersCache, key, rolesList);
79 | LOG.debug("Load User roles[{}] from DB and cache it, key = {}", rolesList, key);
80 | }
81 |
82 | return rolesList;
83 | }
84 |
85 |
86 | private Cache getUsersCache() {
87 | return cacheManager.getCache(CacheNames.USERS_CACHE);
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------