mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-07 01:18:27 +08:00
cache change to Caffeine
This commit is contained in:
parent
8b3c035102
commit
f7966f5b12
@ -366,8 +366,9 @@ subprojects {
|
|||||||
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
||||||
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
||||||
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
|
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: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
|
||||||
|
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
|
||||||
|
|
||||||
//mybatis
|
//mybatis
|
||||||
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
||||||
|
|||||||
@ -318,9 +318,9 @@ subprojects {
|
|||||||
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
||||||
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
||||||
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
|
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: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
|
||||||
|
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
|
||||||
//mybatis
|
//mybatis
|
||||||
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
||||||
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
||||||
|
|||||||
@ -318,9 +318,9 @@ subprojects {
|
|||||||
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
||||||
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
||||||
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
|
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: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
|
||||||
|
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
|
||||||
//mybatis
|
//mybatis
|
||||||
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
||||||
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
||||||
|
|||||||
@ -353,9 +353,9 @@ subprojects {
|
|||||||
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
implementation group: 'com.alibaba', name: 'druid', version: "${druidVersion}"
|
||||||
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: "${druidspringbootstarterVersion}"
|
||||||
implementation group: 'redis.clients', name: 'jedis', version: "${jedisVersion}"
|
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: 'org.liquibase', name: 'liquibase-core', version: '4.3.5'
|
||||||
|
implementation group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: "${caffeineVersion}"
|
||||||
//mybatis
|
//mybatis
|
||||||
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis', version: "${mybatisVersion}"
|
||||||
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
implementation group: 'org.mybatis', name: 'mybatis-spring', version: "${mybatisspringVersion}"
|
||||||
|
|||||||
@ -81,6 +81,7 @@ druidVersion =1.2.8
|
|||||||
druidspringbootstarterVersion =1.2.8
|
druidspringbootstarterVersion =1.2.8
|
||||||
jedisVersion =3.7.0
|
jedisVersion =3.7.0
|
||||||
ehcacheVersion =3.9.6
|
ehcacheVersion =3.9.6
|
||||||
|
caffeineVersion =2.9.2
|
||||||
mybatisVersion =3.5.7
|
mybatisVersion =3.5.7
|
||||||
mybatisspringVersion =2.0.6
|
mybatisspringVersion =2.0.6
|
||||||
#saml
|
#saml
|
||||||
|
|||||||
@ -19,22 +19,23 @@ package org.maxkey.authn.online;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalTime;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
|
|
||||||
public class InMemoryOnlineTicketServices implements OnlineTicketServices{
|
public class InMemoryOnlineTicketServices implements OnlineTicketServices{
|
||||||
private static final Logger _logger = LoggerFactory.getLogger(InMemoryOnlineTicketServices.class);
|
private static final Logger _logger = LoggerFactory.getLogger(InMemoryOnlineTicketServices.class);
|
||||||
|
|
||||||
protected static UserManagedCache<String, OnlineTicket> onlineTicketStore =
|
protected static Cache<String, OnlineTicket> onlineTicketStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OnlineTicket.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofMinutes(30)))
|
.expireAfterWrite(30, TimeUnit.MINUTES)
|
||||||
.build(true);
|
.maximumSize(200000)
|
||||||
|
.build();
|
||||||
|
|
||||||
public InMemoryOnlineTicketServices() {
|
public InMemoryOnlineTicketServices() {
|
||||||
super();
|
super();
|
||||||
@ -47,27 +48,24 @@ public class InMemoryOnlineTicketServices implements OnlineTicketServices{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OnlineTicket remove(String ticketId) {
|
public OnlineTicket remove(String ticketId) {
|
||||||
OnlineTicket ticket=onlineTicketStore.get(ticketId);
|
OnlineTicket ticket=onlineTicketStore.getIfPresent(ticketId);
|
||||||
onlineTicketStore.remove(ticketId);
|
onlineTicketStore.invalidate(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OnlineTicket get(String ticketId) {
|
public OnlineTicket get(String ticketId) {
|
||||||
OnlineTicket ticket=onlineTicketStore.get(ticketId);
|
OnlineTicket ticket=onlineTicketStore.getIfPresent(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValiditySeconds(int validitySeconds) {
|
public void setValiditySeconds(int validitySeconds) {
|
||||||
onlineTicketStore =
|
onlineTicketStore =
|
||||||
UserManagedCacheBuilder.
|
Caffeine.newBuilder()
|
||||||
newUserManagedCacheBuilder(String.class, OnlineTicket.class)
|
.expireAfterWrite(validitySeconds/60, TimeUnit.MINUTES)
|
||||||
.withExpiry(
|
.maximumSize(200000)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
Duration.ofMinutes(validitySeconds/60))
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,22 +17,19 @@
|
|||||||
|
|
||||||
package org.maxkey.authn.support.rememberme;
|
package org.maxkey.authn.support.rememberme;
|
||||||
|
|
||||||
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.constants.ConstantsTimeInterval;
|
import org.maxkey.constants.ConstantsTimeInterval;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
public class InMemoryRemeberMeService extends AbstractRemeberMeService {
|
public class InMemoryRemeberMeService extends AbstractRemeberMeService {
|
||||||
|
|
||||||
protected static final UserManagedCache<String, RemeberMe> remeberMeStore =
|
protected static final Cache<String, RemeberMe> remeberMeStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, RemeberMe.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(
|
.expireAfterWrite(ConstantsTimeInterval.TWO_WEEK, TimeUnit.MINUTES)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
Duration.ofMinutes(ConstantsTimeInterval.TWO_WEEK)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void save(RemeberMe remeberMe) {
|
public void save(RemeberMe remeberMe) {
|
||||||
@ -46,12 +43,12 @@ public class InMemoryRemeberMeService extends AbstractRemeberMeService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RemeberMe read(RemeberMe remeberMe) {
|
public RemeberMe read(RemeberMe remeberMe) {
|
||||||
return remeberMeStore.get(remeberMe.getUsername());
|
return remeberMeStore.getIfPresent(remeberMe.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(String username) {
|
public void remove(String username) {
|
||||||
remeberMeStore.remove(username);
|
remeberMeStore.invalidate(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,29 +17,26 @@
|
|||||||
|
|
||||||
package org.maxkey.password.onetimepwd.token;
|
package org.maxkey.password.onetimepwd.token;
|
||||||
|
|
||||||
import org.ehcache.UserManagedCache;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.ehcache.config.builders.ExpiryPolicyBuilder;
|
|
||||||
import org.ehcache.config.builders.UserManagedCacheBuilder;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
import org.maxkey.constants.ConstantsTimeInterval;
|
|
||||||
import org.maxkey.entity.UserInfo;
|
import org.maxkey.entity.UserInfo;
|
||||||
import org.maxkey.password.onetimepwd.OneTimePassword;
|
import org.maxkey.password.onetimepwd.OneTimePassword;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
public class InMemoryOtpTokenStore extends AbstractOtpTokenStore {
|
public class InMemoryOtpTokenStore extends AbstractOtpTokenStore {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(InMemoryOtpTokenStore.class);
|
private static final Logger logger = LoggerFactory.getLogger(InMemoryOtpTokenStore.class);
|
||||||
|
|
||||||
protected static final UserManagedCache<String, OneTimePassword> optTokenStore =
|
protected static final Cache<String, OneTimePassword> optTokenStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OneTimePassword.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(
|
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
java.time.Duration.ofMinutes(ConstantsTimeInterval.ONE_MINUTE * 5)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void store(UserInfo userInfo, String token, String receiver, String type) {
|
public void store(UserInfo userInfo, String token, String receiver, String type) {
|
||||||
@ -57,7 +54,7 @@ public class InMemoryOtpTokenStore extends AbstractOtpTokenStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validate(UserInfo userInfo, String token, String type, int interval) {
|
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) {
|
if (otp != null) {
|
||||||
DateTime currentdateTime = new DateTime();
|
DateTime currentdateTime = new DateTime();
|
||||||
DateTime oneCreateTime = DateTime.parse(otp.getCreateTime(),
|
DateTime oneCreateTime = DateTime.parse(otp.getCreateTime(),
|
||||||
|
|||||||
@ -23,17 +23,14 @@ import java.sql.SQLException;
|
|||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
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.DateTime;
|
||||||
import org.joda.time.Duration;
|
import org.joda.time.Duration;
|
||||||
import org.joda.time.format.DateTimeFormat;
|
import org.joda.time.format.DateTimeFormat;
|
||||||
import org.maxkey.constants.ConstantsPasswordSetType;
|
import org.maxkey.constants.ConstantsPasswordSetType;
|
||||||
import org.maxkey.constants.ConstantsProperties;
|
import org.maxkey.constants.ConstantsProperties;
|
||||||
import org.maxkey.constants.ConstantsStatus;
|
import org.maxkey.constants.ConstantsStatus;
|
||||||
import org.maxkey.constants.ConstantsTimeInterval;
|
|
||||||
import org.maxkey.crypto.password.PasswordGen;
|
import org.maxkey.crypto.password.PasswordGen;
|
||||||
import org.maxkey.entity.PasswordPolicy;
|
import org.maxkey.entity.PasswordPolicy;
|
||||||
import org.maxkey.entity.UserInfo;
|
import org.maxkey.entity.UserInfo;
|
||||||
@ -63,6 +60,9 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
|||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
public class PasswordPolicyValidator {
|
public class PasswordPolicyValidator {
|
||||||
private static Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class);
|
private static Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class);
|
||||||
|
|
||||||
@ -71,14 +71,10 @@ public class PasswordPolicyValidator {
|
|||||||
"classpath:/top_weak_password.txt";
|
"classpath:/top_weak_password.txt";
|
||||||
|
|
||||||
//Cache PasswordPolicy in memory ONE_HOUR
|
//Cache PasswordPolicy in memory ONE_HOUR
|
||||||
protected static final UserManagedCache<String, PasswordPolicy> passwordPolicyStore =
|
protected static final Cache<String, PasswordPolicy> passwordPolicyStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, PasswordPolicy.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(
|
.expireAfterWrite(60, TimeUnit.MINUTES)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
java.time.Duration.ofMinutes(ConstantsTimeInterval.ONE_HOUR)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
protected PasswordPolicy passwordPolicy;
|
protected PasswordPolicy passwordPolicy;
|
||||||
|
|
||||||
@ -115,7 +111,7 @@ public class PasswordPolicyValidator {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public PasswordPolicy getPasswordPolicy() {
|
public PasswordPolicy getPasswordPolicy() {
|
||||||
passwordPolicy = passwordPolicyStore.get(PASSWORD_POLICY_KEY);
|
passwordPolicy = passwordPolicyStore.getIfPresent(PASSWORD_POLICY_KEY);
|
||||||
|
|
||||||
if (passwordPolicy == null) {
|
if (passwordPolicy == null) {
|
||||||
passwordPolicy = jdbcTemplate.queryForObject(PASSWORD_POLICY_SELECT_STATEMENT,
|
passwordPolicy = jdbcTemplate.queryForObject(PASSWORD_POLICY_SELECT_STATEMENT,
|
||||||
|
|||||||
Binary file not shown.
BIN
maxkey-lib/mybatis-jpa-extra-2.6.jar
Normal file
BIN
maxkey-lib/mybatis-jpa-extra-2.6.jar
Normal file
Binary file not shown.
Binary file not shown.
@ -17,29 +17,25 @@
|
|||||||
|
|
||||||
package org.maxkey.persistence.service;
|
package org.maxkey.persistence.service;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.mybatis.jpa.persistence.JpaBaseService;
|
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.Apps;
|
||||||
import org.maxkey.entity.apps.UserApps;
|
import org.maxkey.entity.apps.UserApps;
|
||||||
import org.maxkey.persistence.mapper.AppsMapper;
|
import org.maxkey.persistence.mapper.AppsMapper;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class AppsService extends JpaBaseService<Apps>{
|
public class AppsService extends JpaBaseService<Apps>{
|
||||||
|
|
||||||
protected final static UserManagedCache<String, Apps> appsDetailsCacheStore =
|
protected final static Cache<String, Apps> appsDetailsCacheStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Apps.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(
|
.expireAfterWrite(60, TimeUnit.MINUTES)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
Duration.ofHours(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
public AppsService() {
|
public AppsService() {
|
||||||
super(AppsMapper.class);
|
super(AppsMapper.class);
|
||||||
@ -50,7 +46,6 @@ public class AppsService extends JpaBaseService<Apps>{
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AppsMapper getMapper() {
|
public AppsMapper getMapper() {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return (AppsMapper)super.getMapper();
|
return (AppsMapper)super.getMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +70,7 @@ public class AppsService extends JpaBaseService<Apps>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Apps getCacheAppDetails(String appId) {
|
public Apps getCacheAppDetails(String appId) {
|
||||||
Apps appDetails=appsDetailsCacheStore.get(appId);
|
Apps appDetails=appsDetailsCacheStore.getIfPresent(appId);
|
||||||
return appDetails;
|
return appDetails;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,21 +17,21 @@
|
|||||||
|
|
||||||
package org.maxkey.authz.cas.endpoint.ticket.pgt;
|
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.RandomServiceTicketServices;
|
||||||
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
|
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 {
|
public class InMemoryProxyGrantingTicketServices extends RandomServiceTicketServices {
|
||||||
|
|
||||||
protected final static UserManagedCache<String, Ticket> casTicketStore =
|
protected final static Cache<String, Ticket> casTicketStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofHours(1)))
|
.expireAfterWrite(60, TimeUnit.MINUTES)
|
||||||
.build(true);
|
.build();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -41,15 +41,15 @@ public class InMemoryProxyGrantingTicketServices extends RandomServiceTicketServ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Ticket remove(String ticketId) {
|
public Ticket remove(String ticketId) {
|
||||||
Ticket ticket=casTicketStore.get(ticketId);
|
Ticket ticket=casTicketStore.getIfPresent(ticketId);
|
||||||
casTicketStore.remove(ticketId);
|
casTicketStore.invalidate(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Ticket get(String ticket) {
|
public Ticket get(String ticket) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
return casTicketStore.get(ticket);
|
return casTicketStore.getIfPresent(ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,21 +17,21 @@
|
|||||||
|
|
||||||
package org.maxkey.authz.cas.endpoint.ticket.st;
|
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.RandomServiceTicketServices;
|
||||||
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
|
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 {
|
public class InMemoryTicketServices extends RandomServiceTicketServices {
|
||||||
|
|
||||||
protected final static UserManagedCache<String, Ticket> casTicketStore =
|
protected final static Cache<String, Ticket> casTicketStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(60)))
|
.expireAfterWrite(60, TimeUnit.MINUTES)
|
||||||
.build(true);
|
.build();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -41,8 +41,8 @@ public class InMemoryTicketServices extends RandomServiceTicketServices {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Ticket remove(String ticketId) {
|
public Ticket remove(String ticketId) {
|
||||||
Ticket ticket=casTicketStore.get(ticketId);
|
Ticket ticket=casTicketStore.getIfPresent(ticketId);
|
||||||
casTicketStore.remove(ticketId);
|
casTicketStore.invalidate(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,22 +17,21 @@
|
|||||||
|
|
||||||
package org.maxkey.authz.cas.endpoint.ticket.tgt;
|
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.RandomServiceTicketServices;
|
||||||
import org.maxkey.authz.cas.endpoint.ticket.Ticket;
|
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 {
|
public class InMemoryTicketGrantingTicketServices extends RandomServiceTicketServices {
|
||||||
|
|
||||||
protected final static UserManagedCache<String, Ticket> casTicketGrantingTicketStore =
|
protected final static Cache<String, Ticket> casTicketGrantingTicketStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Ticket.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofDays(2)))
|
.expireAfterWrite(2, TimeUnit.DAYS)
|
||||||
.build(true);
|
.build();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void store(String ticketId, Ticket ticket) {
|
public void store(String ticketId, Ticket ticket) {
|
||||||
@ -41,14 +40,14 @@ public class InMemoryTicketGrantingTicketServices extends RandomServiceTicketSer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Ticket remove(String ticketId) {
|
public Ticket remove(String ticketId) {
|
||||||
Ticket ticket=casTicketGrantingTicketStore.get(ticketId);
|
Ticket ticket=casTicketGrantingTicketStore.getIfPresent(ticketId);
|
||||||
casTicketGrantingTicketStore.remove(ticketId);
|
casTicketGrantingTicketStore.invalidate(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Ticket get(String ticketId) {
|
public Ticket get(String ticketId) {
|
||||||
Ticket ticket=casTicketGrantingTicketStore.get(ticketId);
|
Ticket ticket=casTicketGrantingTicketStore.getIfPresent(ticketId);
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,46 +32,6 @@ import org.springframework.util.StringUtils;
|
|||||||
*/
|
*/
|
||||||
public abstract class OAuth2Utils {
|
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.
|
* Parses a string parameter value into a set of strings.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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;
|
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
|
* @return the grant type if known, or null otherwise
|
||||||
*/
|
*/
|
||||||
public String getGrantType() {
|
public String getGrantType() {
|
||||||
if (getRequestParameters().containsKey(OAuth2Utils.GRANT_TYPE)) {
|
if (getRequestParameters().containsKey(OAuth2Constants.PARAMETER.GRANT_TYPE)) {
|
||||||
return getRequestParameters().get(OAuth2Utils.GRANT_TYPE);
|
return getRequestParameters().get(OAuth2Constants.PARAMETER.GRANT_TYPE);
|
||||||
}
|
}
|
||||||
if (getRequestParameters().containsKey(OAuth2Utils.RESPONSE_TYPE)) {
|
if (getRequestParameters().containsKey(OAuth2Constants.PARAMETER.RESPONSE_TYPE)) {
|
||||||
String response = getRequestParameters().get(OAuth2Utils.RESPONSE_TYPE);
|
String response = getRequestParameters().get(OAuth2Constants.PARAMETER.RESPONSE_TYPE);
|
||||||
if (response.contains("token")) {
|
if (response.contains("token")) {
|
||||||
return "implicit";
|
return "implicit";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
package org.maxkey.authz.oauth2.provider;
|
package org.maxkey.authz.oauth2.provider;
|
||||||
|
|
||||||
import org.maxkey.authz.oauth2.common.exceptions.InvalidScopeException;
|
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.authz.oauth2.provider.endpoint.TokenEndpoint;
|
||||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.common.util.OAuth2Utils;
|
||||||
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
import org.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
||||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
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 static Log logger = LogFactory.getLog(ApprovalStoreUserApprovalHandler.class);
|
||||||
|
|
||||||
private String scopePrefix = OAuth2Utils.SCOPE_PREFIX;
|
private String scopePrefix = OAuth2Constants.PARAMETER.SCOPE_PREFIX;
|
||||||
|
|
||||||
private ApprovalStore approvalStore;
|
private ApprovalStore approvalStore;
|
||||||
|
|
||||||
@ -232,12 +233,12 @@ public class ApprovalStoreUserApprovalHandler implements UserApprovalHandler, In
|
|||||||
model.putAll(authorizationRequest.getRequestParameters());
|
model.putAll(authorizationRequest.getRequestParameters());
|
||||||
Map<String, String> scopes = new LinkedHashMap<String, String>();
|
Map<String, String> scopes = new LinkedHashMap<String, String>();
|
||||||
for (String scope : authorizationRequest.getScope()) {
|
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(),
|
for (Approval approval : approvalStore.getApprovals(userAuthentication.getName(),
|
||||||
authorizationRequest.getClientId())) {
|
authorizationRequest.getClientId())) {
|
||||||
if (authorizationRequest.getScope().contains(approval.getScope())) {
|
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");
|
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ package org.maxkey.authz.oauth2.provider.approval;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.maxkey.authz.oauth2.provider.AuthorizationRequest;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ import org.springframework.security.core.Authentication;
|
|||||||
*/
|
*/
|
||||||
public class DefaultUserApprovalHandler implements UserApprovalHandler {
|
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
|
* @param approvalParameter the approvalParameter to set
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import java.util.Set;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.maxkey.authz.oauth2.common.OAuth2AccessToken;
|
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.AuthorizationRequest;
|
||||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||||
import org.maxkey.authz.oauth2.provider.ClientRegistrationException;
|
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 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;
|
private TokenStore tokenStore;
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.maxkey.authn.SigninPrincipal;
|
import org.maxkey.authn.SigninPrincipal;
|
||||||
import org.maxkey.authz.oauth2.common.OAuth2Constants;
|
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.AuthorizationRequest;
|
||||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
||||||
import org.maxkey.authz.oauth2.provider.approval.Approval;
|
import org.maxkey.authz.oauth2.provider.approval.Approval;
|
||||||
@ -99,13 +98,13 @@ public class OAuth20AccessConfirmationEndpoint {
|
|||||||
model.put("oauth_version", "oauth 2.0");
|
model.put("oauth_version", "oauth 2.0");
|
||||||
Map<String, String> scopes = new LinkedHashMap<String, String>();
|
Map<String, String> scopes = new LinkedHashMap<String, String>();
|
||||||
for (String scope : clientAuth.getScope()) {
|
for (String scope : clientAuth.getScope()) {
|
||||||
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
|
scopes.put(OAuth2Constants.PARAMETER.SCOPE_PREFIX + scope, "false");
|
||||||
}
|
}
|
||||||
String principal =
|
String principal =
|
||||||
((SigninPrincipal) WebContext.getAuthentication().getPrincipal()).getUsername();
|
((SigninPrincipal) WebContext.getAuthentication().getPrincipal()).getUsername();
|
||||||
for (Approval approval : approvalStore.getApprovals(principal, client.getClientId())) {
|
for (Approval approval : approvalStore.getApprovals(principal, client.getClientId())) {
|
||||||
if (clientAuth.getScope().contains(approval.getScope())) {
|
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");
|
approval.getStatus() == ApprovalStatus.APPROVED ? "true" : "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -23,6 +23,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
@ -47,6 +48,9 @@ import org.springframework.util.Assert;
|
|||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
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.
|
* 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);
|
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 JsonMapper mapper = createJsonMapper();
|
||||||
|
|
||||||
private static final String CLIENT_FIELDS_FOR_UPDATE = "RESOURCE_IDS, SCOPE, "
|
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) {
|
public ClientDetails loadClientByClientId(String clientId) {
|
||||||
ClientDetails details;
|
//TODO: cache in memory
|
||||||
|
ClientDetails details = clientDetailsCache.getIfPresent(clientId);
|
||||||
|
if(details == null) {
|
||||||
try {
|
try {
|
||||||
details = jdbcTemplate.queryForObject(selectClientDetailsSql, new ClientDetailsRowMapper(), clientId);
|
details = jdbcTemplate.queryForObject(selectClientDetailsSql, new ClientDetailsRowMapper(), clientId);
|
||||||
|
clientDetailsCache.put(clientId, details);
|
||||||
} catch (EmptyResultDataAccessException e) {
|
} catch (EmptyResultDataAccessException e) {
|
||||||
throw new NoSuchClientException("No client with requested id: " + clientId);
|
throw new NoSuchClientException("No client with requested id: " + clientId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,12 +17,11 @@
|
|||||||
|
|
||||||
package org.maxkey.authz.oauth2.provider.code;
|
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 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.
|
* 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
|
* @author Dave Syer
|
||||||
*/
|
*/
|
||||||
public class InMemoryAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
|
public class InMemoryAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
|
||||||
protected final static UserManagedCache<String, OAuth2Authentication> authorizationCodeStore =
|
protected final static Cache<String, OAuth2Authentication> authorizationCodeStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, OAuth2Authentication.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(60)))
|
.expireAfterWrite(3, TimeUnit.MINUTES)
|
||||||
.build(true);
|
.build();
|
||||||
@Override
|
@Override
|
||||||
protected void store(String code, OAuth2Authentication authentication) {
|
protected void store(String code, OAuth2Authentication authentication) {
|
||||||
authorizationCodeStore.put(code, authentication);
|
authorizationCodeStore.put(code, authentication);
|
||||||
@ -42,8 +41,8 @@ public class InMemoryAuthorizationCodeServices extends RandomValueAuthorizationC
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2Authentication remove(String code) {
|
public OAuth2Authentication remove(String code) {
|
||||||
OAuth2Authentication auth = authorizationCodeStore.get(code);
|
OAuth2Authentication auth = authorizationCodeStore.getIfPresent(code);
|
||||||
authorizationCodeStore.remove(code);
|
authorizationCodeStore.invalidate(code);
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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.refresh.RefreshTokenGranter;
|
||||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
|
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestFactory;
|
||||||
import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
|
import org.maxkey.authz.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||||
|
import org.maxkey.configuration.ApplicationConfig;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
@ -56,23 +57,28 @@ public class AbstractEndpoint implements InitializingBean {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("oauth20TokenServices")
|
@Qualifier("oauth20TokenServices")
|
||||||
AuthorizationServerTokenServices tokenServices ;
|
protected AuthorizationServerTokenServices tokenServices ;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("oauth20JdbcClientDetailsService")
|
@Qualifier("oauth20JdbcClientDetailsService")
|
||||||
private ClientDetailsService clientDetailsService;
|
protected ClientDetailsService clientDetailsService;
|
||||||
@Autowired
|
|
||||||
@Qualifier("oAuth2RequestFactory")
|
|
||||||
private OAuth2RequestFactory oAuth2RequestFactory;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("oAuth2RequestFactory")
|
@Qualifier("oAuth2RequestFactory")
|
||||||
private OAuth2RequestFactory defaultOAuth2RequestFactory;
|
protected OAuth2RequestFactory oAuth2RequestFactory;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("oAuth2RequestFactory")
|
||||||
|
protected OAuth2RequestFactory defaultOAuth2RequestFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("oauth20UserAuthenticationManager")
|
@Qualifier("oauth20UserAuthenticationManager")
|
||||||
AuthenticationManager authenticationManager;
|
AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("applicationConfig")
|
||||||
|
protected ApplicationConfig applicationConfig;
|
||||||
|
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
if (tokenGranter == null) {
|
if (tokenGranter == null) {
|
||||||
|
|||||||
@ -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.implicit.ImplicitTokenRequest;
|
||||||
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
import org.maxkey.authz.oauth2.provider.request.DefaultOAuth2RequestValidator;
|
||||||
import org.maxkey.util.HttpEncoder;
|
import org.maxkey.util.HttpEncoder;
|
||||||
import org.maxkey.configuration.ApplicationConfig;
|
|
||||||
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
import org.maxkey.entity.apps.oauth2.provider.ClientDetails;
|
||||||
import org.maxkey.web.WebContext;
|
import org.maxkey.web.WebContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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.authentication.InsufficientAuthenticationException;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@ -69,7 +66,6 @@ import org.springframework.web.util.UriComponentsBuilder;
|
|||||||
import org.springframework.web.util.UriTemplate;
|
import org.springframework.web.util.UriTemplate;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.maxkey.authz.oauth2.provider.ClientDetailsService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <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";
|
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 RedirectResolver redirectResolver = new DefaultRedirectResolver();
|
||||||
|
|
||||||
private UserApprovalHandler userApprovalHandler = new DefaultUserApprovalHandler();
|
private UserApprovalHandler userApprovalHandler = new DefaultUserApprovalHandler();
|
||||||
@ -121,6 +109,30 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
|||||||
this.errorPage = errorPage;
|
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")
|
@ApiOperation(value = "OAuth 2.0 认证接口", notes = "传递参数client_id,response_type,redirect_uri等",httpMethod="GET")
|
||||||
@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.GET)
|
@RequestMapping(value = OAuth2Constants.ENDPOINT.ENDPOINT_AUTHORIZE, method = RequestMethod.GET)
|
||||||
public ModelAndView authorize(
|
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(
|
public View approveOrDeny(
|
||||||
@RequestParam Map<String, String> approvalParameters,
|
@RequestParam Map<String, String> approvalParameters,
|
||||||
Map<String, ?> model,
|
Map<String, ?> model,
|
||||||
@ -529,28 +542,4 @@ public class AuthorizationEndpoint extends AbstractEndpoint {
|
|||||||
this.oauth2RequestValidator = oauth2RequestValidator;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -210,7 +210,7 @@ public class TokenEndpointAuthenticationFilter implements Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> map = getSingleValueMap(request);
|
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 authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(map);
|
||||||
|
|
||||||
authorizationRequest.setScope(getScope(request));
|
authorizationRequest.setScope(getScope(request));
|
||||||
|
|||||||
@ -69,14 +69,14 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
|
|||||||
|
|
||||||
public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
|
public AuthorizationRequest createAuthorizationRequest(Map<String, String> authorizationParameters) {
|
||||||
|
|
||||||
String clientId = authorizationParameters.get(OAuth2Utils.CLIENT_ID);
|
String clientId = authorizationParameters.get(OAuth2Constants.PARAMETER.CLIENT_ID);
|
||||||
String state = authorizationParameters.get(OAuth2Utils.STATE);
|
String state = authorizationParameters.get(OAuth2Constants.PARAMETER.STATE);
|
||||||
String redirectUri = authorizationParameters.get(OAuth2Utils.REDIRECT_URI);
|
String redirectUri = authorizationParameters.get(OAuth2Constants.PARAMETER.REDIRECT_URI);
|
||||||
//oauth 2.1 PKCE
|
//oauth 2.1 PKCE
|
||||||
String codeChallenge = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE);
|
String codeChallenge = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE);
|
||||||
String codeChallengeMethod = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE_METHOD);
|
String codeChallengeMethod = authorizationParameters.get(OAuth2Constants.PARAMETER.CODE_CHALLENGE_METHOD);
|
||||||
Set<String> responseTypes = OAuth2Utils.parseParameterList(authorizationParameters
|
Set<String> responseTypes = OAuth2Utils.parseParameterList(authorizationParameters
|
||||||
.get(OAuth2Utils.RESPONSE_TYPE));
|
.get(OAuth2Constants.PARAMETER.RESPONSE_TYPE));
|
||||||
|
|
||||||
Set<String> scopes = extractScopes(authorizationParameters, clientId);
|
Set<String> scopes = extractScopes(authorizationParameters, clientId);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
|
|||||||
|
|
||||||
public TokenRequest createTokenRequest(Map<String, String> requestParameters, ClientDetails authenticatedClient) {
|
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 (clientId == null) {
|
||||||
// if the clientId wasn't passed in in the map, we add pull it from the authenticated client object
|
// if the clientId wasn't passed in in the map, we add pull it from the authenticated client object
|
||||||
clientId = authenticatedClient.getClientId();
|
clientId = authenticatedClient.getClientId();
|
||||||
@ -108,7 +108,7 @@ public class DefaultOAuth2RequestFactory implements OAuth2RequestFactory {
|
|||||||
throw new InvalidClientException("Given client ID does not match authenticated client");
|
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);
|
Set<String> scopes = extractScopes(requestParameters, clientId);
|
||||||
TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scopes, grantType);
|
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) {
|
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);
|
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
|
||||||
|
|
||||||
if ((scopes == null || scopes.isEmpty())) {
|
if ((scopes == null || scopes.isEmpty())) {
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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.DefaultTokenServices;
|
||||||
import org.maxkey.authz.oauth2.provider.token.TokenStore;
|
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.InMemoryTokenStore;
|
||||||
import org.maxkey.authz.oauth2.provider.token.store.JdbcTokenStore;
|
|
||||||
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
|
import org.maxkey.authz.oauth2.provider.token.store.RedisTokenStore;
|
||||||
import org.maxkey.jobs.DynamicGroupsJob;
|
import org.maxkey.jobs.DynamicGroupsJob;
|
||||||
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
import org.maxkey.password.onetimepwd.AbstractOtpAuthn;
|
||||||
@ -79,16 +78,14 @@ public class MaxKeyMgtConfig implements InitializingBean {
|
|||||||
JdbcTemplate jdbcTemplate,
|
JdbcTemplate jdbcTemplate,
|
||||||
RedisConnectionFactory jedisConnectionFactory) {
|
RedisConnectionFactory jedisConnectionFactory) {
|
||||||
TokenStore tokenStore = null;
|
TokenStore tokenStore = null;
|
||||||
if (persistence == 0) {
|
if (persistence == 2) {
|
||||||
tokenStore = new InMemoryTokenStore();
|
|
||||||
_logger.debug("InMemoryTokenStore");
|
|
||||||
} else if (persistence == 1) {
|
|
||||||
tokenStore = new JdbcTokenStore(jdbcTemplate);
|
|
||||||
_logger.debug("JdbcTokenStore");
|
|
||||||
} else if (persistence == 2) {
|
|
||||||
tokenStore = new RedisTokenStore(jedisConnectionFactory);
|
tokenStore = new RedisTokenStore(jedisConnectionFactory);
|
||||||
_logger.debug("RedisTokenStore");
|
_logger.debug("RedisTokenStore");
|
||||||
|
}else {
|
||||||
|
tokenStore = new InMemoryTokenStore();
|
||||||
|
_logger.debug("InMemoryTokenStore");
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokenStore;
|
return tokenStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,16 +17,12 @@
|
|||||||
|
|
||||||
package org.maxkey.web.interceptor;
|
package org.maxkey.web.interceptor;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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.crypto.password.PasswordReciprocal;
|
||||||
import org.maxkey.entity.apps.Apps;
|
import org.maxkey.entity.apps.Apps;
|
||||||
import org.maxkey.persistence.service.AppsService;
|
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.stereotype.Component;
|
||||||
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* basic认证Interceptor处理.
|
* basic认证Interceptor处理.
|
||||||
* @author Crystal.Sea
|
* @author Crystal.Sea
|
||||||
@ -48,14 +47,10 @@ import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
|||||||
public class RestApiPermissionAdapter implements AsyncHandlerInterceptor {
|
public class RestApiPermissionAdapter implements AsyncHandlerInterceptor {
|
||||||
private static final Logger _logger = LoggerFactory.getLogger(RestApiPermissionAdapter.class);
|
private static final Logger _logger = LoggerFactory.getLogger(RestApiPermissionAdapter.class);
|
||||||
|
|
||||||
protected static final UserManagedCache<String, Apps> appsCacheStore =
|
protected static final Cache<String, Apps> appsCacheStore =
|
||||||
UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, Apps.class)
|
Caffeine.newBuilder()
|
||||||
.withExpiry(
|
.expireAfterWrite(60, TimeUnit.MINUTES)
|
||||||
ExpiryPolicyBuilder.timeToLiveExpiration(
|
.build();
|
||||||
Duration.ofMinutes(ConstantsTimeInterval.ONE_HOUR)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.build(true);
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
AppsService appsService;
|
AppsService appsService;
|
||||||
@ -83,7 +78,7 @@ public class RestApiPermissionAdapter implements AsyncHandlerInterceptor {
|
|||||||
String appId = headerCredential.getUsername();
|
String appId = headerCredential.getUsername();
|
||||||
String appSecret = headerCredential.getCredential();
|
String appSecret = headerCredential.getCredential();
|
||||||
_logger.trace("appId "+ appId+" , appSecret " + appSecret);
|
_logger.trace("appId "+ appId+" , appSecret " + appSecret);
|
||||||
Apps app = appsCacheStore.get(appId);
|
Apps app = appsCacheStore.getIfPresent(appId);
|
||||||
if (app == null) {
|
if (app == null) {
|
||||||
app = appsService.get(appId);
|
app = appsService.get(appId);
|
||||||
appsCacheStore.put(appId, app);
|
appsCacheStore.put(appId, app);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user