cache change to Caffeine

This commit is contained in:
Crystal.Sea 2021-10-11 12:58:43 +08:00
parent 8b3c035102
commit f7966f5b12
34 changed files with 199 additions and 875 deletions

View File

@ -366,8 +366,9 @@ subprojects {
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
//mybatis
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"

View File

@ -318,9 +318,9 @@ subprojects {
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
//mybatis
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"

View File

@ -318,9 +318,9 @@ subprojects {
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
//mybatis
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"

View File

@ -353,9 +353,9 @@ subprojects {
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.ehcache', name: 'ehcache', version: "${ehcacheVersion}"
//implementation group: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
//mybatis
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"

View File

@ -81,6 +81,7 @@ druidVersion =1.2.8
druidspringbootstarterVersion =1.2.8
jedisVersion =3.7.0
ehcacheVersion =3.9.6
caffeineVersion =2.9.2
mybatisVersion =3.5.7
mybatisspringVersion =2.0.6
#saml

View File

@ -19,22 +19,23 @@ package org.maxkey.authn.online;
import java.time.Duration;
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryOnlineTicketServices implements OnlineTicketServices{
private static final Logger _logger = LoggerFactory.getLogger(InMemoryOnlineTicketServices.class);
protected static UserManagedCache<String, OnlineTicket> onlineTicketStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OnlineTicket.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30)))
.build(true);
protected static Cache<String, OnlineTicket> onlineTicketStore =
Caffeine.newBuilder()
.expireAfterWrite(30, TimeUnit.MINUTES)
.maximumSize(200000)
.build();
public InMemoryOnlineTicketServices() {
super();
@ -47,27 +48,24 @@ public class InMemoryOnlineTicketServices implements OnlineTicketServices{
@Override
public OnlineTicket remove(String ticketId) {
OnlineTicket ticket=onlineTicketStore.get(ticketId);
onlineTicketStore.remove(ticketId);
OnlineTicket ticket=onlineTicketStore.getIfPresent(ticketId);
onlineTicketStore.invalidate(ticketId);
return ticket;
}
@Override
public OnlineTicket get(String ticketId) {
OnlineTicket ticket=onlineTicketStore.get(ticketId);
OnlineTicket ticket=onlineTicketStore.getIfPresent(ticketId);
return ticket;
}
@Override
public void setValiditySeconds(int validitySeconds) {
onlineTicketStore =
UserManagedCacheBuilder.
newUserManagedCacheBuilder(String.class, OnlineTicket.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofMinutes(validitySeconds/60))
)
.build(true);
Caffeine.newBuilder()
.expireAfterWrite(validitySeconds/60, TimeUnit.MINUTES)
.maximumSize(200000)
.build();
}

View File

@ -17,22 +17,19 @@
package org.maxkey.authn.support.rememberme;
import java.time.Duration;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import java.util.concurrent.TimeUnit;
import org.maxkey.constants.ConstantsTimeInterval;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryRemeberMeService extends AbstractRemeberMeService {
protected static final UserManagedCache<String, RemeberMe> remeberMeStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, RemeberMe.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofMinutes(ConstantsTimeInterval.TWO_WEEK)
)
)
.build(true);
protected static final Cache<String, RemeberMe> remeberMeStore =
Caffeine.newBuilder()
.expireAfterWrite(ConstantsTimeInterval.TWO_WEEK, TimeUnit.MINUTES)
.build();
@Override
public void save(RemeberMe remeberMe) {
@ -46,12 +43,12 @@ public class InMemoryRemeberMeService extends AbstractRemeberMeService {
@Override
public RemeberMe read(RemeberMe remeberMe) {
return remeberMeStore.get(remeberMe.getUsername());
return remeberMeStore.getIfPresent(remeberMe.getUsername());
}
@Override
public void remove(String username) {
remeberMeStore.remove(username);
remeberMeStore.invalidate(username);
}
}

View File

@ -17,29 +17,26 @@
package org.maxkey.password.onetimepwd.token;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.format.DateTimeFormat;
import org.maxkey.constants.ConstantsTimeInterval;
import org.maxkey.entity.UserInfo;
import org.maxkey.password.onetimepwd.OneTimePassword;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryOtpTokenStore extends AbstractOtpTokenStore {
private static final Logger logger = LoggerFactory.getLogger(InMemoryOtpTokenStore.class);
protected static final UserManagedCache<String, OneTimePassword> optTokenStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OneTimePassword.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
java.time.Duration.ofMinutes(ConstantsTimeInterval.ONE_MINUTE * 5)
)
)
.build(true);
protected static final Cache<String, OneTimePassword> optTokenStore =
Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
@Override
public void store(UserInfo userInfo, String token, String receiver, String type) {
@ -57,7 +54,7 @@ public class InMemoryOtpTokenStore extends AbstractOtpTokenStore {
@Override
public boolean validate(UserInfo userInfo, String token, String type, int interval) {
OneTimePassword otp = optTokenStore.get(userInfo.getUsername() + "_" + type + "_" + token);
OneTimePassword otp = optTokenStore.getIfPresent(userInfo.getUsername() + "_" + type + "_" + token);
if (otp != null) {
DateTime currentdateTime = new DateTime();
DateTime oneCreateTime = DateTime.parse(otp.getCreateTime(),

View File

@ -23,17 +23,14 @@ import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.format.DateTimeFormat;
import org.maxkey.constants.ConstantsPasswordSetType;
import org.maxkey.constants.ConstantsProperties;
import org.maxkey.constants.ConstantsStatus;
import org.maxkey.constants.ConstantsTimeInterval;
import org.maxkey.crypto.password.PasswordGen;
import org.maxkey.entity.PasswordPolicy;
import org.maxkey.entity.UserInfo;
@ -63,6 +60,9 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.BadCredentialsException;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class PasswordPolicyValidator {
private static Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class);
@ -71,14 +71,10 @@ public class PasswordPolicyValidator {
"classpath:/top_weak_password.txt";
//Cache PasswordPolicy in memory ONE_HOUR
protected static final UserManagedCache<String, PasswordPolicy> passwordPolicyStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, PasswordPolicy.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
java.time.Duration.ofMinutes(ConstantsTimeInterval.ONE_HOUR)
)
)
.build(true);
protected static final Cache<String, PasswordPolicy> passwordPolicyStore =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
protected PasswordPolicy passwordPolicy;
@ -115,7 +111,7 @@ public class PasswordPolicyValidator {
* @return
*/
public PasswordPolicy getPasswordPolicy() {
passwordPolicy = passwordPolicyStore.get(PASSWORD_POLICY_KEY);
passwordPolicy = passwordPolicyStore.getIfPresent(PASSWORD_POLICY_KEY);
if (passwordPolicy == null) {
passwordPolicy = jdbcTemplate.queryForObject(PASSWORD_POLICY_SELECT_STATEMENT,

Binary file not shown.

Binary file not shown.

View File

@ -17,29 +17,25 @@
package org.maxkey.persistence.service;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.mybatis.jpa.persistence.JpaBaseService;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.entity.apps.Apps;
import org.maxkey.entity.apps.UserApps;
import org.maxkey.persistence.mapper.AppsMapper;
import org.springframework.stereotype.Repository;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
@Repository
public class AppsService extends JpaBaseService<Apps>{
protected final static UserManagedCache<String, Apps> appsDetailsCacheStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Apps.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofHours(1)
)
)
.build(true);
protected final static Cache<String, Apps> appsDetailsCacheStore =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
public AppsService() {
super(AppsMapper.class);
@ -50,7 +46,6 @@ public class AppsService extends JpaBaseService<Apps>{
*/
@Override
public AppsMapper getMapper() {
// TODO Auto-generated method stub
return (AppsMapper)super.getMapper();
}
@ -75,7 +70,7 @@ public class AppsService extends JpaBaseService<Apps>{
}
public Apps getCacheAppDetails(String appId) {
Apps appDetails=appsDetailsCacheStore.get(appId);
Apps appDetails=appsDetailsCacheStore.getIfPresent(appId);
return appDetails;
}
}

View File

@ -17,21 +17,21 @@
package org.maxkey.authz.cas.endpoint.ticket.pgt;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.authz.cas.endpoint.ticket.RandomServiceTicketServices;
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryProxyGrantingTicketServices extends RandomServiceTicketServices {
protected final static UserManagedCache<String, Ticket> casTicketStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofHours(1)))
.build(true);
protected final static Cache<String, Ticket> casTicketStore =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
@Override
@ -41,15 +41,15 @@ public class InMemoryProxyGrantingTicketServices extends RandomServiceTicketServ
@Override
public Ticket remove(String ticketId) {
Ticket ticket=casTicketStore.get(ticketId);
casTicketStore.remove(ticketId);
Ticket ticket=casTicketStore.getIfPresent(ticketId);
casTicketStore.invalidate(ticketId);
return ticket;
}
@Override
public Ticket get(String ticket) {
// TODO Auto-generated method stub
return casTicketStore.get(ticket);
return casTicketStore.getIfPresent(ticket);
}
}

View File

@ -17,21 +17,21 @@
package org.maxkey.authz.cas.endpoint.ticket.st;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.authz.cas.endpoint.ticket.RandomServiceTicketServices;
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryTicketServices extends RandomServiceTicketServices {
protected final static UserManagedCache<String, Ticket> casTicketStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(60)))
.build(true);
protected final static Cache<String, Ticket> casTicketStore =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
@Override
@ -41,8 +41,8 @@ public class InMemoryTicketServices extends RandomServiceTicketServices {
@Override
public Ticket remove(String ticketId) {
Ticket ticket=casTicketStore.get(ticketId);
casTicketStore.remove(ticketId);
Ticket ticket=casTicketStore.getIfPresent(ticketId);
casTicketStore.invalidate(ticketId);
return ticket;
}

View File

@ -17,22 +17,21 @@
package org.maxkey.authz.cas.endpoint.ticket.tgt;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.authz.cas.endpoint.ticket.RandomServiceTicketServices;
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class InMemoryTicketGrantingTicketServices extends RandomServiceTicketServices {
protected final static UserManagedCache<String, Ticket> casTicketGrantingTicketStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofDays(2)))
.build(true);
protected final static Cache<String, Ticket> casTicketGrantingTicketStore =
Caffeine.newBuilder()
.expireAfterWrite(2, TimeUnit.DAYS)
.build();
@Override
public void store(String ticketId, Ticket ticket) {
@ -41,14 +40,14 @@ public class InMemoryTicketGrantingTicketServices extends RandomServiceTicketSer
@Override
public Ticket remove(String ticketId) {
Ticket ticket=casTicketGrantingTicketStore.get(ticketId);
casTicketGrantingTicketStore.remove(ticketId);
Ticket ticket=casTicketGrantingTicketStore.getIfPresent(ticketId);
casTicketGrantingTicketStore.invalidate(ticketId);
return ticket;
}
@Override
public Ticket get(String ticketId) {
Ticket ticket=casTicketGrantingTicketStore.get(ticketId);
Ticket ticket=casTicketGrantingTicketStore.getIfPresent(ticketId);
return ticket;
}

View File

@ -32,46 +32,6 @@ import org.springframework.util.StringUtils;
*/
public abstract class OAuth2Utils {
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String CLIENT_ID = "client_id";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String STATE = "state";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String SCOPE = "scope";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String REDIRECT_URI = "redirect_uri";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String RESPONSE_TYPE = "response_type";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String USER_OAUTH_APPROVAL = "user_oauth_approval";
/**
* Constant to use as a prefix for scope approval
*/
public static final String SCOPE_PREFIX = "scope.";
/**
* Constant to use while parsing and formatting parameter maps for OAuth2 requests
*/
public static final String GRANT_TYPE = "grant_type";
/**
* Parses a string parameter value into a set of strings.
*

View File

@ -24,7 +24,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.springframework.security.core.GrantedAuthority;
/**
@ -228,11 +228,11 @@ public class OAuth2Request extends BaseRequest implements Serializable {
* @return the grant type if known, or null otherwise
*/
public String getGrantType() {
if (getRequestParameters().containsKey(OAuth2Utils.GRANT_TYPE)) {
return getRequestParameters().get(OAuth2Utils.GRANT_TYPE);
if (getRequestParameters().containsKey(OAuth2Constants.PARAMETER.GRANT_TYPE)) {
return getRequestParameters().get(OAuth2Constants.PARAMETER.GRANT_TYPE);
}
if (getRequestParameters().containsKey(OAuth2Utils.RESPONSE_TYPE)) {
String response = getRequestParameters().get(OAuth2Utils.RESPONSE_TYPE);
if (getRequestParameters().containsKey(OAuth2Constants.PARAMETER.RESPONSE_TYPE)) {
String response = getRequestParameters().get(OAuth2Constants.PARAMETER.RESPONSE_TYPE);
if (response.contains("token")) {
return "implicit";
}

View File

@ -18,7 +18,6 @@
package org.maxkey.authz.oauth2.provider;
import org.maxkey.authz.oauth2.common.exceptions.InvalidScopeException;
import org.maxkey.authz.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.maxkey.authz.oauth2.provider.endpoint.TokenEndpoint;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;

View File

@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
@ -48,7 +49,7 @@ public class ApprovalStoreUserApprovalHandler implements UserApprovalHandler, In
private static Log logger = LogFactory.getLog(ApprovalStoreUserApprovalHandler.class);
private String scopePrefix = OAuth2Utils.SCOPE_PREFIX;
private String scopePrefix = OAuth2Constants.PARAMETER.SCOPE_PREFIX;
private ApprovalStore approvalStore;
@ -232,12 +233,12 @@ public class ApprovalStoreUserApprovalHandler implements UserApprovalHandler, In
model.putAll(authorizationRequest.getRequestParameters());
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : authorizationRequest.getScope()) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + scope, "false");
}
for (Approval approval : approvalStore.getApprovals(userAuthentication.getName(),
authorizationRequest.getClientId())) {
if (authorizationRequest.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
}
}

View File

@ -19,7 +19,7 @@ package org.maxkey.authz.oauth2.provider.approval;
import java.util.HashMap;
import java.util.Map;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
import org.springframework.security.core.Authentication;
@ -31,7 +31,7 @@ import org.springframework.security.core.Authentication;
*/
public class DefaultUserApprovalHandler implements UserApprovalHandler {
private String approvalParameter = OAuth2Utils.USER_OAUTH_APPROVAL;
private String approvalParameter = OAuth2Constants.PARAMETER.USER_OAUTH_APPROVAL;
/**
* @param approvalParameter the approvalParameter to set

View File

@ -23,7 +23,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
import org.maxkey.authz.oauth2.provider.ClientRegistrationException;
@ -46,7 +46,7 @@ public class TokenStoreUserApprovalHandler implements UserApprovalHandler, Initi
private static Log logger = LogFactory.getLog(TokenStoreUserApprovalHandler.class);
private String approvalParameter = OAuth2Utils.USER_OAUTH_APPROVAL;
private String approvalParameter = OAuth2Constants.PARAMETER.USER_OAUTH_APPROVAL;
private TokenStore tokenStore;

View File

@ -21,7 +21,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.maxkey.authn.SigninPrincipal;
import org.maxkey.authz.oauth2.common.OAuth2Constants;
import org.maxkey.authz.oauth2.common.util.OAuth2Utils;
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
import org.maxkey.authz.oauth2.provider.approval.Approval;
@ -99,13 +98,13 @@ public class OAuth20AccessConfirmationEndpoint {
model.put("oauth_version", "oauth 2.0");
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + scope, "false");
}
String principal =
((SigninPrincipal) WebContext.getAuthentication().getPrincipal()).getUsername();
for (Approval approval : approvalStore.getApprovals(principal, client.getClientId())) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright 2008 Web Cohesion
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.maxkey.authz.oauth2.provider.client;
import java.util.HashMap;
import java.util.Map;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
import org.maxkey.authz.oauth2.provider.ClientRegistrationException;
import org.maxkey.authz.oauth2.provider.NoSuchClientException;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
/**
* Basic, in-memory implementation of the client details service.
*
* @author Ryan Heaton
*/
public class InMemoryClientDetailsService implements ClientDetailsService {
private Map<String, ClientDetails> clientDetailsStore = new HashMap<String, ClientDetails>();
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
ClientDetails details = clientDetailsStore.get(clientId);
if (details == null) {
throw new NoSuchClientException("No client with requested id: " + clientId);
}
return details;
}
public void setClientDetailsStore(Map<String, ? extends ClientDetails> clientDetailsStore) {
this.clientDetailsStore = new HashMap<String, ClientDetails>(clientDetailsStore);
}
}

View File

@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.sql.DataSource;
@ -47,6 +48,9 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* Basic, JDBC implementation of the client details service.
*/
@ -54,6 +58,12 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
private static final Log logger = LogFactory.getLog(JdbcClientDetailsService.class);
protected final static Cache<String, ClientDetails> clientDetailsCache =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.maximumSize(200000)
.build();
private JsonMapper mapper = createJsonMapper();
private static final String CLIENT_FIELDS_FOR_UPDATE = "RESOURCE_IDS, SCOPE, "
@ -116,13 +126,16 @@ public class JdbcClientDetailsService implements ClientDetailsService, ClientReg
}
public ClientDetails loadClientByClientId(String clientId) {
ClientDetails details;
//TODO: cache in memory
ClientDetails details = clientDetailsCache.getIfPresent(clientId);
if(details == null) {
try {
details = jdbcTemplate.queryForObject(selectClientDetailsSql, new ClientDetailsRowMapper(), clientId);
clientDetailsCache.put(clientId, details);
} catch (EmptyResultDataAccessException e) {
throw new NoSuchClientException("No client with requested id: " + clientId);
}
}
return details;
}

View File

@ -17,12 +17,11 @@
package org.maxkey.authz.oauth2.provider.code;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* Implementation of authorization code services that stores the codes and authentication in memory.
@ -31,10 +30,10 @@ import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
* @author Dave Syer
*/
public class InMemoryAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
protected final static UserManagedCache<String, OAuth2Authentication> authorizationCodeStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OAuth2Authentication.class)
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(60)))
.build(true);
protected final static Cache<String, OAuth2Authentication> authorizationCodeStore =
Caffeine.newBuilder()
.expireAfterWrite(3, TimeUnit.MINUTES)
.build();
@Override
protected void store(String code, OAuth2Authentication authentication) {
authorizationCodeStore.put(code, authentication);
@ -42,8 +41,8 @@ public class InMemoryAuthorizationCodeServices extends RandomValueAuthorizationC
@Override
public OAuth2Authentication remove(String code) {
OAuth2Authentication auth = authorizationCodeStore.get(code);
authorizationCodeStore.remove(code);
OAuth2Authentication auth = authorizationCodeStore.getIfPresent(code);
authorizationCodeStore.invalidate(code);
return auth;
}

View File

@ -1,101 +0,0 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.maxkey.authz.oauth2.provider.code;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.sql.DataSource;
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
import org.maxkey.util.SerializationUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.SqlLobValue;
import org.springframework.util.Assert;
/**
* Implementation of authorization code services that stores the codes and
* authentication in a database.
*
* @author Crystal.Sea
*/
public class JdbcAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
private static final String DEFAULT_SELECT_STATEMENT = "select code, authentication from oauth_code where code = ?";
private static final String DEFAULT_INSERT_STATEMENT = "insert into oauth_code (code, authentication) values (?, ?)";
private static final String DEFAULT_DELETE_STATEMENT = "delete from oauth_code where code = ?";
private String selectAuthenticationSql = DEFAULT_SELECT_STATEMENT;
private String insertAuthenticationSql = DEFAULT_INSERT_STATEMENT;
private String deleteAuthenticationSql = DEFAULT_DELETE_STATEMENT;
private final JdbcTemplate jdbcTemplate;
public JdbcAuthorizationCodeServices(DataSource dataSource) {
Assert.notNull(dataSource, "DataSource required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public JdbcAuthorizationCodeServices(JdbcTemplate jdbcTemplate) {
Assert.notNull(jdbcTemplate, "jdbcTemplate required");
this.jdbcTemplate = jdbcTemplate;
}
@Override
protected void store(String code, OAuth2Authentication authentication) {
jdbcTemplate.update(insertAuthenticationSql,
new Object[] { code, new SqlLobValue(SerializationUtils.serialize(authentication)) },
new int[] { Types.VARCHAR, Types.BLOB });
}
public OAuth2Authentication remove(String code) {
OAuth2Authentication authentication;
try {
authentication = jdbcTemplate.queryForObject(selectAuthenticationSql,
new RowMapper<OAuth2Authentication>() {
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
return SerializationUtils.deserialize(rs.getBytes("authentication"));
}
}, code);
} catch (EmptyResultDataAccessException e) {
return null;
}
if (authentication != null) {
jdbcTemplate.update(deleteAuthenticationSql, code);
}
return authentication;
}
public void setSelectAuthenticationSql(String selectAuthenticationSql) {
this.selectAuthenticationSql = selectAuthenticationSql;
}
public void setInsertAuthenticationSql(String insertAuthenticationSql) {
this.insertAuthenticationSql = insertAuthenticationSql;
}
public void setDeleteAuthenticationSql(String deleteAuthenticationSql) {
this.deleteAuthenticationSql = deleteAuthenticationSql;
}
}

View File

@ -34,6 +34,7 @@ import org.maxkey.authz.oauth2.provider.password.ResourceOwnerPasswordTokenGrant
import org.maxkey.authz.oauth2.provider.refresh.RefreshTokenGranter;
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
import org.maxkey.configuration.ApplicationConfig;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@ -56,23 +57,28 @@ public class AbstractEndpoint implements InitializingBean {
@Autowired
@Qualifier("oauth20TokenServices")
AuthorizationServerTokenServices tokenServices ;
protected AuthorizationServerTokenServices tokenServices ;
@Autowired
@Qualifier("oauth20JdbcClientDetailsService")
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("oAuth2RequestFactory")
private OAuth2RequestFactory oAuth2RequestFactory;
protected ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("oAuth2RequestFactory")
private OAuth2RequestFactory defaultOAuth2RequestFactory;
protected OAuth2RequestFactory oAuth2RequestFactory;
@Autowired
@Qualifier("oAuth2RequestFactory")
protected OAuth2RequestFactory defaultOAuth2RequestFactory;
@Autowired
@Qualifier("oauth20UserAuthenticationManager")
AuthenticationManager authenticationManager;
@Autowired
@Qualifier("applicationConfig")
protected ApplicationConfig applicationConfig;
public void afterPropertiesSet() throws Exception {
if (tokenGranter == null) {

View File

@ -43,13 +43,10 @@ import org.maxkey.authz.oauth2.provider.code.AuthorizationCodeServices;
import org.maxkey.authz.oauth2.provider.implicit.ImplicitTokenRequest;
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
import org.maxkey.util.HttpEncoder;
import org.maxkey.configuration.ApplicationConfig;
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
import org.maxkey.web.WebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
@ -69,7 +66,6 @@ import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriTemplate;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
/**
* <p>
@ -96,14 +92,6 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
private static final String OAUTH_V20_AUTHORIZATION_URL = "%s" + OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE + "?client_id=%s&response_type=code&redirect_uri=%s&approval_prompt=auto";
@Autowired
@Qualifier("oauth20JdbcClientDetailsService")
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("applicationConfig")
protected ApplicationConfig applicationConfig;
private RedirectResolver redirectResolver = new DefaultRedirectResolver();
private UserApprovalHandler userApprovalHandler = new DefaultUserApprovalHandler();
@ -121,6 +109,30 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
this.errorPage = errorPage;
}
@ApiOperation(value = "OAuth 2.0 认证接口", notes = "传递参数应用ID自动完成跳转认证拼接",httpMethod="GET")
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}")
public ModelAndView authorize(
HttpServletRequest request,
HttpServletResponse response,
@PathVariable("id") String id){
ClientDetails clientDetails =getClientDetailsService().loadClientByClientId(id);
_logger.debug(""+clientDetails);
String authorizationUrl = "";
try {
authorizationUrl = String.format(OAUTH_V20_AUTHORIZATION_URL,
applicationConfig.getServerPrefix(),
clientDetails.getClientId(),
HttpEncoder.encode(clientDetails.getRegisteredRedirectUri().toArray()[0].toString())
);
} catch (Exception e) {
e.printStackTrace();
}
_logger.debug("authorizationUrl "+authorizationUrl);
return WebContext.redirect(authorizationUrl);
}
@ApiOperation(value = "OAuth 2.0 认证接口", notes = "传递参数client_id,response_type,redirect_uri等",httpMethod="GET")
@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.GET)
public ModelAndView authorize(
@ -204,7 +216,8 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
}
@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
//approval must post
@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.POST, params = OAuth2Constants.PARAMETER.USER_OAUTH_APPROVAL)
public View approveOrDeny(
@RequestParam Map<String, String> approvalParameters,
Map<String, ?> model,
@ -529,28 +542,4 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
this.oauth2RequestValidator = oauth2RequestValidator;
}
@ApiOperation(value = "OAuth 2.0 认证接口", notes = "传递参数应用ID自动完成跳转认证拼接",httpMethod="GET")
@RequestMapping(OAuth2Constants.ENDPOINT.ENDPOINT_BASE + "/{id}")
public ModelAndView authorize(
HttpServletRequest request,
HttpServletResponse response,
@PathVariable("id") String id){
ClientDetails clientDetails =clientDetailsService.loadClientByClientId(id);
_logger.debug(""+clientDetails);
String authorizationUrl = "";
try {
authorizationUrl = String.format(OAUTH_V20_AUTHORIZATION_URL,
applicationConfig.getServerPrefix(),
clientDetails.getClientId(),
HttpEncoder.encode(clientDetails.getRegisteredRedirectUri().toArray()[0].toString())
);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
_logger.debug("authorizationUrl "+authorizationUrl);
return WebContext.redirect(authorizationUrl);
}
}

View File

@ -210,7 +210,7 @@ public class TokenEndpointAuthenticationFilter implements Filter {
}
Map<String, String> map = getSingleValueMap(request);
map.put(OAuth2Utils.CLIENT_ID, clientAuth.getName());
map.put(OAuth2Constants.PARAMETER.CLIENT_ID, clientAuth.getName());
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(map);
authorizationRequest.setScope(getScope(request));

View File

@ -69,14 +69,14 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
String clientId = authorizationParameters.get(OAuth2Utils.CLIENT_ID);
String state = authorizationParameters.get(OAuth2Utils.STATE);
String redirectUri = authorizationParameters.get(OAuth2Utils.REDIRECT_URI);
String clientId = authorizationParameters.get(OAuth2Constants.PARAMETER.CLIENT_ID);
String state = authorizationParameters.get(OAuth2Constants.PARAMETER.STATE);
String redirectUri = authorizationParameters.get(OAuth2Constants.PARAMETER.REDIRECT_URI);
//oauth 2.1 PKCE
String codeChallenge = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE);
String codeChallengeMethod = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE_METHOD);
Set<String> responseTypes = OAuth2Utils.parseParameterList(authorizationParameters
.get(OAuth2Utils.RESPONSE_TYPE));
.get(OAuth2Constants.PARAMETER.RESPONSE_TYPE));
Set<String> scopes = extractScopes(authorizationParameters, clientId);
@ -97,7 +97,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
String clientId = requestParameters.get(OAuth2Utils.CLIENT_ID);
String clientId = requestParameters.get(OAuth2Constants.PARAMETER.CLIENT_ID);
if (clientId == null) {
// if the clientId wasn't passed in in the map, we add pull it from the authenticated client object
clientId = authenticatedClient.getClientId();
@ -108,7 +108,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
throw new InvalidClientException("Given client ID does not match authenticated client");
}
}
String grantType = requestParameters.get(OAuth2Utils.GRANT_TYPE);
String grantType = requestParameters.get(OAuth2Constants.PARAMETER.GRANT_TYPE);
Set<String> scopes = extractScopes(requestParameters, clientId);
TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scopes, grantType);
@ -127,7 +127,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
}
private Set<String> extractScopes(Map<String, String> requestParameters, String clientId) {
Set<String> scopes = OAuth2Utils.parseParameterList(requestParameters.get(OAuth2Utils.SCOPE));
Set<String> scopes = OAuth2Utils.parseParameterList(requestParameters.get(OAuth2Constants.PARAMETER.SCOPE));
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
if ((scopes == null || scopes.isEmpty())) {

View File

@ -1,469 +0,0 @@
/*
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.maxkey.authz.oauth2.provider.token.store;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
import org.maxkey.authz.oauth2.common.OAuth2RefreshToken;
import org.maxkey.authz.oauth2.provider.OAuth2Authentication;
import org.maxkey.authz.oauth2.provider.token.AuthenticationKeyGenerator;
import org.maxkey.authz.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
import org.maxkey.authz.oauth2.provider.token.TokenStore;
import org.maxkey.util.SerializationUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.SqlLobValue;
import org.springframework.util.Assert;
/**
* Implementation of token services that stores tokens in a database.
*
* @author Ken Dombeck
* @author Luke Taylor
* @author Dave Syer
*/
public class JdbcTokenStore implements TokenStore {
private static final Log LOG = LogFactory.getLog(JdbcTokenStore.class);
private static final String DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT = "insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)";
private static final String DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_access_token where token_id = ?";
private static final String DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_access_token where token_id = ?";
private static final String DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT = "select token_id, token from oauth_access_token where authentication_id = ?";
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ? and client_id = ?";
private static final String DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT = "select token_id, token from oauth_access_token where user_name = ?";
private static final String DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT = "select token_id, token from oauth_access_token where client_id = ?";
private static final String DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT = "delete from oauth_access_token where token_id = ?";
private static final String DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT = "delete from oauth_access_token where refresh_token = ?";
private static final String DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT = "insert into oauth_refresh_token (token_id, token, authentication) values (?, ?, ?)";
private static final String DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT = "select token_id, token from oauth_refresh_token where token_id = ?";
private static final String DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT = "select token_id, authentication from oauth_refresh_token where token_id = ?";
private static final String DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT = "delete from oauth_refresh_token where token_id = ?";
private String insertAccessTokenSql = DEFAULT_ACCESS_TOKEN_INSERT_STATEMENT;
private String selectAccessTokenSql = DEFAULT_ACCESS_TOKEN_SELECT_STATEMENT;
private String selectAccessTokenAuthenticationSql = DEFAULT_ACCESS_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
private String selectAccessTokenFromAuthenticationSql = DEFAULT_ACCESS_TOKEN_FROM_AUTHENTICATION_SELECT_STATEMENT;
private String selectAccessTokensFromUserNameAndClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_AND_CLIENT_SELECT_STATEMENT;
private String selectAccessTokensFromUserNameSql = DEFAULT_ACCESS_TOKENS_FROM_USERNAME_SELECT_STATEMENT;
private String selectAccessTokensFromClientIdSql = DEFAULT_ACCESS_TOKENS_FROM_CLIENTID_SELECT_STATEMENT;
private String deleteAccessTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_STATEMENT;
private String insertRefreshTokenSql = DEFAULT_REFRESH_TOKEN_INSERT_STATEMENT;
private String selectRefreshTokenSql = DEFAULT_REFRESH_TOKEN_SELECT_STATEMENT;
private String selectRefreshTokenAuthenticationSql = DEFAULT_REFRESH_TOKEN_AUTHENTICATION_SELECT_STATEMENT;
private String deleteRefreshTokenSql = DEFAULT_REFRESH_TOKEN_DELETE_STATEMENT;
private String deleteAccessTokenFromRefreshTokenSql = DEFAULT_ACCESS_TOKEN_DELETE_FROM_REFRESH_TOKEN_STATEMENT;
private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
private final JdbcTemplate jdbcTemplate;
public JdbcTokenStore(DataSource dataSource) {
Assert.notNull(dataSource, "DataSource required");
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public JdbcTokenStore(JdbcTemplate jdbcTemplate) {
Assert.notNull(jdbcTemplate, "jdbcTemplate required");
this.jdbcTemplate = jdbcTemplate;
}
public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
this.authenticationKeyGenerator = authenticationKeyGenerator;
}
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
OAuth2AccessToken accessToken = null;
String key = authenticationKeyGenerator.extractKey(authentication);
try {
accessToken = jdbcTemplate.queryForObject(selectAccessTokenFromAuthenticationSql,
new RowMapper<OAuth2AccessToken>() {
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
return deserializeAccessToken(rs.getBytes(2));
}
}, key);
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.debug("Failed to find access token for authentication " + authentication);
}
} catch (IllegalArgumentException e) {
LOG.error("Could not extract access token for authentication " + authentication, e);
}
if (accessToken != null
&& !key.equals(authenticationKeyGenerator.extractKey(readAuthentication(accessToken.getValue())))) {
removeAccessToken(accessToken.getValue());
// Keep the store consistent (maybe the same user is represented by this
// authentication but the details have
// changed)
storeAccessToken(accessToken, authentication);
}
return accessToken;
}
public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
String refreshToken = null;
if (token.getRefreshToken() != null) {
refreshToken = token.getRefreshToken().getValue();
}
if (readAccessToken(token.getValue()) != null) {
removeAccessToken(token.getValue());
}
jdbcTemplate.update(insertAccessTokenSql,
new Object[] { extractTokenKey(token.getValue()), new SqlLobValue(serializeAccessToken(token)),
authenticationKeyGenerator.extractKey(authentication),
authentication.isClientOnly() ? null : authentication.getName(),
authentication.getOAuth2Request().getClientId(),
new SqlLobValue(serializeAuthentication(authentication)), extractTokenKey(refreshToken) },
new int[] { Types.VARCHAR, Types.BLOB, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BLOB,
Types.VARCHAR });
}
public OAuth2AccessToken readAccessToken(String tokenValue) {
OAuth2AccessToken accessToken = null;
try {
accessToken = jdbcTemplate.queryForObject(selectAccessTokenSql, new RowMapper<OAuth2AccessToken>() {
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
return deserializeAccessToken(rs.getBytes(2));
}
}, extractTokenKey(tokenValue));
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for token " + tokenValue);
}
} catch (IllegalArgumentException e) {
LOG.warn("Failed to deserialize access token for " + tokenValue, e);
removeAccessToken(tokenValue);
}
return accessToken;
}
public void removeAccessToken(OAuth2AccessToken token) {
removeAccessToken(token.getValue());
}
public void removeAccessToken(String tokenValue) {
jdbcTemplate.update(deleteAccessTokenSql, extractTokenKey(tokenValue));
}
public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
return readAuthentication(token.getValue());
}
public OAuth2Authentication readAuthentication(String token) {
OAuth2Authentication authentication = null;
try {
authentication = jdbcTemplate.queryForObject(selectAccessTokenAuthenticationSql,
new RowMapper<OAuth2Authentication>() {
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
return deserializeAuthentication(rs.getBytes(2));
}
}, extractTokenKey(token));
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for token " + token);
}
} catch (IllegalArgumentException e) {
LOG.warn("Failed to deserialize authentication for " + token, e);
removeAccessToken(token);
}
return authentication;
}
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
jdbcTemplate.update(insertRefreshTokenSql,
new Object[] { extractTokenKey(refreshToken.getValue()),
new SqlLobValue(serializeRefreshToken(refreshToken)),
new SqlLobValue(serializeAuthentication(authentication)) },
new int[] { Types.VARCHAR, Types.BLOB, Types.BLOB });
}
public OAuth2RefreshToken readRefreshToken(String token) {
OAuth2RefreshToken refreshToken = null;
try {
refreshToken = jdbcTemplate.queryForObject(selectRefreshTokenSql, new RowMapper<OAuth2RefreshToken>() {
public OAuth2RefreshToken mapRow(ResultSet rs, int rowNum) throws SQLException {
return deserializeRefreshToken(rs.getBytes(2));
}
}, extractTokenKey(token));
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find refresh token for token " + token);
}
} catch (IllegalArgumentException e) {
LOG.warn("Failed to deserialize refresh token for token " + token, e);
removeRefreshToken(token);
}
return refreshToken;
}
public void removeRefreshToken(OAuth2RefreshToken token) {
removeRefreshToken(token.getValue());
}
public void removeRefreshToken(String token) {
jdbcTemplate.update(deleteRefreshTokenSql, extractTokenKey(token));
}
public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
return readAuthenticationForRefreshToken(token.getValue());
}
public OAuth2Authentication readAuthenticationForRefreshToken(String value) {
OAuth2Authentication authentication = null;
try {
authentication = jdbcTemplate.queryForObject(selectRefreshTokenAuthenticationSql,
new RowMapper<OAuth2Authentication>() {
public OAuth2Authentication mapRow(ResultSet rs, int rowNum) throws SQLException {
return deserializeAuthentication(rs.getBytes(2));
}
}, extractTokenKey(value));
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for token " + value);
}
} catch (IllegalArgumentException e) {
LOG.warn("Failed to deserialize access token for " + value, e);
removeRefreshToken(value);
}
return authentication;
}
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
}
public void removeAccessTokenUsingRefreshToken(String refreshToken) {
jdbcTemplate.update(deleteAccessTokenFromRefreshTokenSql, new Object[] { extractTokenKey(refreshToken) },
new int[] { Types.VARCHAR });
}
public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
try {
accessTokens = jdbcTemplate.query(selectAccessTokensFromClientIdSql, new SafeAccessTokenRowMapper(),
clientId);
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for clientId " + clientId);
}
}
accessTokens = removeNulls(accessTokens);
return accessTokens;
}
public Collection<OAuth2AccessToken> findTokensByUserName(String userName) {
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
try {
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameSql, new SafeAccessTokenRowMapper(),
userName);
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled())
LOG.info("Failed to find access token for userName " + userName);
}
accessTokens = removeNulls(accessTokens);
return accessTokens;
}
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
List<OAuth2AccessToken> accessTokens = new ArrayList<OAuth2AccessToken>();
try {
accessTokens = jdbcTemplate.query(selectAccessTokensFromUserNameAndClientIdSql,
new SafeAccessTokenRowMapper(), userName, clientId);
} catch (EmptyResultDataAccessException e) {
if (LOG.isInfoEnabled()) {
LOG.info("Failed to find access token for clientId " + clientId + " and userName " + userName);
}
}
accessTokens = removeNulls(accessTokens);
return accessTokens;
}
private List<OAuth2AccessToken> removeNulls(List<OAuth2AccessToken> accessTokens) {
List<OAuth2AccessToken> tokens = new ArrayList<OAuth2AccessToken>();
for (OAuth2AccessToken token : accessTokens) {
if (token != null) {
tokens.add(token);
}
}
return tokens;
}
protected String extractTokenKey(String value) {
if (value == null) {
return null;
}
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
byte[] bytes = digest.digest(value.getBytes("UTF-8"));
return String.format("%032x", new BigInteger(1, bytes));
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
private final class SafeAccessTokenRowMapper implements RowMapper<OAuth2AccessToken> {
public OAuth2AccessToken mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
return deserializeAccessToken(rs.getBytes(2));
} catch (IllegalArgumentException e) {
String token = rs.getString(1);
jdbcTemplate.update(deleteAccessTokenSql, token);
return null;
}
}
}
protected byte[] serializeAccessToken(OAuth2AccessToken token) {
return SerializationUtils.serialize(token);
}
protected byte[] serializeRefreshToken(OAuth2RefreshToken token) {
return SerializationUtils.serialize(token);
}
protected byte[] serializeAuthentication(OAuth2Authentication authentication) {
return SerializationUtils.serialize(authentication);
}
protected OAuth2AccessToken deserializeAccessToken(byte[] token) {
return SerializationUtils.deserialize(token);
}
protected OAuth2RefreshToken deserializeRefreshToken(byte[] token) {
return SerializationUtils.deserialize(token);
}
protected OAuth2Authentication deserializeAuthentication(byte[] authentication) {
return SerializationUtils.deserialize(authentication);
}
public void setInsertAccessTokenSql(String insertAccessTokenSql) {
this.insertAccessTokenSql = insertAccessTokenSql;
}
public void setSelectAccessTokenSql(String selectAccessTokenSql) {
this.selectAccessTokenSql = selectAccessTokenSql;
}
public void setDeleteAccessTokenSql(String deleteAccessTokenSql) {
this.deleteAccessTokenSql = deleteAccessTokenSql;
}
public void setInsertRefreshTokenSql(String insertRefreshTokenSql) {
this.insertRefreshTokenSql = insertRefreshTokenSql;
}
public void setSelectRefreshTokenSql(String selectRefreshTokenSql) {
this.selectRefreshTokenSql = selectRefreshTokenSql;
}
public void setDeleteRefreshTokenSql(String deleteRefreshTokenSql) {
this.deleteRefreshTokenSql = deleteRefreshTokenSql;
}
public void setSelectAccessTokenAuthenticationSql(String selectAccessTokenAuthenticationSql) {
this.selectAccessTokenAuthenticationSql = selectAccessTokenAuthenticationSql;
}
public void setSelectRefreshTokenAuthenticationSql(String selectRefreshTokenAuthenticationSql) {
this.selectRefreshTokenAuthenticationSql = selectRefreshTokenAuthenticationSql;
}
public void setSelectAccessTokenFromAuthenticationSql(String selectAccessTokenFromAuthenticationSql) {
this.selectAccessTokenFromAuthenticationSql = selectAccessTokenFromAuthenticationSql;
}
public void setDeleteAccessTokenFromRefreshTokenSql(String deleteAccessTokenFromRefreshTokenSql) {
this.deleteAccessTokenFromRefreshTokenSql = deleteAccessTokenFromRefreshTokenSql;
}
public void setSelectAccessTokensFromUserNameSql(String selectAccessTokensFromUserNameSql) {
this.selectAccessTokensFromUserNameSql = selectAccessTokensFromUserNameSql;
}
public void setSelectAccessTokensFromUserNameAndClientIdSql(String selectAccessTokensFromUserNameAndClientIdSql) {
this.selectAccessTokensFromUserNameAndClientIdSql = selectAccessTokensFromUserNameAndClientIdSql;
}
public void setSelectAccessTokensFromClientIdSql(String selectAccessTokensFromClientIdSql) {
this.selectAccessTokensFromClientIdSql = selectAccessTokensFromClientIdSql;
}
}

View File

@ -22,7 +22,6 @@ import org.maxkey.authz.oauth2.provider.client.JdbcClientDetailsService;
import org.maxkey.authz.oauth2.provider.token.DefaultTokenServices;
import org.maxkey.authz.oauth2.provider.token.TokenStore;
import org.maxkey.authz.oauth2.provider.token.store.InMemoryTokenStore;
import org.maxkey.authz.oauth2.provider.token.store.JdbcTokenStore;
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
import org.maxkey.jobs.DynamicGroupsJob;
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
@ -79,16 +78,14 @@ public class MaxKeyMgtConfig implements InitializingBean {
JdbcTemplate jdbcTemplate,
RedisConnectionFactory jedisConnectionFactory) {
TokenStore tokenStore = null;
if (persistence == 0) {
tokenStore = new InMemoryTokenStore();
_logger.debug("InMemoryTokenStore");
} else if (persistence == 1) {
tokenStore = new JdbcTokenStore(jdbcTemplate);
_logger.debug("JdbcTokenStore");
} else if (persistence == 2) {
if (persistence == 2) {
tokenStore = new RedisTokenStore(jedisConnectionFactory);
_logger.debug("RedisTokenStore");
}else {
tokenStore = new InMemoryTokenStore();
_logger.debug("InMemoryTokenStore");
}
return tokenStore;
}

View File

@ -17,16 +17,12 @@
package org.maxkey.web.interceptor;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.UserManagedCacheBuilder;
import org.maxkey.constants.ConstantsTimeInterval;
import org.maxkey.crypto.password.PasswordReciprocal;
import org.maxkey.entity.apps.Apps;
import org.maxkey.persistence.service.AppsService;
@ -39,6 +35,9 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* basic认证Interceptor处理.
* @author Crystal.Sea
@ -48,14 +47,10 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor;
public class RestApiPermissionAdapter implements AsyncHandlerInterceptor {
private static final Logger _logger = LoggerFactory.getLogger(RestApiPermissionAdapter.class);
protected static final UserManagedCache<String, Apps> appsCacheStore =
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Apps.class)
.withExpiry(
ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofMinutes(ConstantsTimeInterval.ONE_HOUR)
)
)
.build(true);
protected static final Cache<String, Apps> appsCacheStore =
Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.build();
@Autowired
AppsService appsService;
@ -83,7 +78,7 @@ public class RestApiPermissionAdapter implements AsyncHandlerInterceptor {
String appId = headerCredential.getUsername();
String appSecret = headerCredential.getCredential();
_logger.trace("appId "+ appId+" , appSecret " + appSecret);
Apps app = appsCacheStore.get(appId);
Apps app = appsCacheStore.getIfPresent(appId);
if (app == null) {
app = appsService.get(appId);
appsCacheStore.put(appId, app);