配置
#cas.tgc.crypto.signing.key=qHdKMqzs/SMAKoIpp262pNuaNXi9LjpvRW3PRWJaZn2e677QjWJd9ONcim9mJJkR #cas.tgc.crypto.signing.key-size=512 #cas.tgc.crypto.encryption.key=zU+d+O1aDcQmzOSsrJj1pFXdv9PkYPLJ #cas.tgc.crypto.encryption.key-size=256 #cas.tgc.crypto.alg=AES #cas.tgc.crypto.enabled=true #cas.tgc.crypto.strategy-type=ENCRYPT_AND_SIGN
CasCookieConfiguration
根据配置实例化处理类
@ConditionalOnMissingBean(
name = {"ticketGrantingTicketCookieGenerator"}
)
@Bean
@RefreshScope
public CasCookieBuilder ticketGrantingTicketCookieGenerator() {
TicketGrantingCookieProperties tgc = this.casProperties.getTgc();
return new TicketGrantingCookieRetrievingCookieGenerator(CookieUtils.buildCookieGenerationContext(tgc), this.cookieValueManager());
}构造类
ticketGrantingTicketCookieGenerator
public CookieRetrievingCookieGenerator(final CookieGenerationContext context, final CookieValueManager casCookieValueManager) {
super.setCookieName(context.getName());
super.setCookiePath(context.getPath());
super.setCookieMaxAge(context.getMaxAge());
super.setCookieSecure(context.isSecure());
super.setCookieHttpOnly(context.isHttpOnly());
this.setCookieDomain(context.getDomain());
this.cookieGenerationContext = context;
this.casCookieValueManager = casCookieValueManager;
}解码逻辑
1、已经登录成功
2、获取tgt 触发点
InitialFlowSetupAction ::configureWebflowForTicketGrantingTicket
private String configureWebflowForTicketGrantingTicket(final RequestContext context) {
HttpServletRequest request = WebUtils.getHttpServletRequestFromExternalWebflowContext(context);
HttpServletResponse response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);
String ticketGrantingTicketId = this.ticketGrantingTicketCookieGenerator.retrieveCookieValue(request);
TicketGrantingTicket ticket = this.ticketRegistrySupport.getTicketGrantingTicket(ticketGrantingTicketId);
if (ticket != null) {
WebUtils.putTicketGrantingTicketInScopes(context, ticket.getId());
return ticket.getId();
} else {
this.ticketGrantingTicketCookieGenerator.removeCookie(response);
WebUtils.putTicketGrantingTicketInScopes(context, "");
return null;
}
}3、获取tgt实现类
TicketGrantingCookieRetrievingCookieGenerator
CookieRetrievingCookieGenerator
@Override
public String retrieveCookieValue(final HttpServletRequest request) {
try {
if (StringUtils.isBlank(getCookieName())) {
throw new InvalidCookieException("Cookie name is undefined");
}
var cookie = org.springframework.web.util.WebUtils.getCookie(request, Objects.requireNonNull(getCookieName()));
if (cookie == null) {
val cookieValue = request.getHeader(getCookieName());
if (StringUtils.isNotBlank(cookieValue)) {
LOGGER.trace("Found cookie [{}] under header name [{}]", cookieValue, getCookieName());
cookie = createCookie(cookieValue);
}
}
if (cookie == null) {
val cookieValue = request.getParameter(getCookieName());
if (StringUtils.isNotBlank(cookieValue)) {
LOGGER.trace("Found cookie [{}] under request parameter name [{}]", cookieValue, getCookieName());
cookie = createCookie(cookieValue);
}
}
return Optional.ofNullable(cookie)
.map(ck -> this.casCookieValueManager.obtainCookieValue(ck, request))
.orElse(null);
} catch (final Exception e) {
LoggingUtils.warn(LOGGER, e);
}
return null;
}3、EncryptedCookieValueManager 获取cookie,这里开始验签 解密
EncryptedCookieValueManager ::obtainCookieValue
@Override
public String obtainCookieValue(final String cookie, final HttpServletRequest request) {
val decoded = cipherExecutor.decode(cookie, ArrayUtils.EMPTY_OBJECT_ARRAY);
if (decoded == null) {
LOGGER.trace("Could not decode cookie value [{}] for cookie", cookie);
return null;
}
val cookieValue = decoded.toString();
LOGGER.trace("Decoded cookie value is [{}]", cookieValue);
if (StringUtils.isBlank(cookieValue)) {
LOGGER.trace("Retrieved decoded cookie value is blank. Failed to decode cookie");
return null;
}
return obtainValueFromCompoundCookie(cookieValue, request);
}4、加解密执行器
TicketGrantingCookieCipherExecutor extends BaseStringCipherExecutor
这里初始化的时候就根据配置的类型比如aes聚合了一个对象 Key secretKeyEncryptionKey
然后根据Key去获取加解密类进行验签解密
private String verifyAndDecrypt(final Serializable value) {
val currentValue = value.toString().getBytes(StandardCharsets.UTF_8);
val encoded = FunctionUtils.doIf(this.signingEnabled, () -> {
LOGGER.trace("Attempting to verify signature based on signing key defined by [{}]", getSigningKeySetting());
return verifySignature(currentValue);
}, () -> currentValue).get();
if (encoded != null && encoded.length > 0) {
val encodedObj = new String(encoded, StandardCharsets.UTF_8);
if (isEncryptionPossible()) {
LOGGER.trace("Attempting to decrypt value based on encryption key defined by [{}]", getEncryptionKeySetting());
return EncodingUtils.decryptJwtValue(this.secretKeyEncryptionKey, encodedObj);
}
return encodedObj;
}
return null;
} AbstractCipherExecutor
这里验签好像是使用的jdk的工具
protected byte[] verifySignature(final byte[] value) {
if (this.signingKey == null) {
return value;
}
try {
if (this.signingKey instanceof RSAPrivateKey) {
val privKey = RSAPrivateKey.class.cast(this.signingKey);
val keySpec = new RSAPublicKeySpec(privKey.getModulus(), RSA_PUBLIC_KEY_EXPONENT);
val pubKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
return EncodingUtils.verifyJwsSignature(pubKey, value);
}
return EncodingUtils.verifyJwsSignature(this.signingKey, value);
} catch (final Exception e) {
throw new IllegalArgumentException(e);
}
}5、解密
BaseStringCipherExecutor
EncodingUtils.decryptJwtValue(this.secretKeyEncryptionKey, encodedObj);
EncodingUtils
这工具类整合了jwt加密解密的所有功能 依赖于JsonWebEncryption
JsonWebEncryption来自jose4j 0.7.8
util调用传入参数 Key secretKeyEncryptionKey
public static String decryptJwtValue(final Key secretKeyEncryptionKey, final String value) {
try {
val jwe = new JsonWebEncryption();
jwe.setKey(secretKeyEncryptionKey);
jwe.setCompactSerialization(value);
LOGGER.trace("Decrypting value...");
return jwe.getPayload();
} catch (final Exception e) {
if (LOGGER.isTraceEnabled()) {
throw new DecryptionException(e);
}
throw new DecryptionException();
}
}jwe解密
private void decrypt() throws JoseException
{
KeyManagementAlgorithm keyManagementModeAlg = getKeyManagementModeAlgorithm();
ContentEncryptionAlgorithm contentEncryptionAlg = getContentEncryptionAlgorithm();
ContentEncryptionKeyDescriptor contentEncryptionKeyDesc = contentEncryptionAlg.getContentEncryptionKeyDescriptor();
checkCrit();
CryptoPrimitive cryptoPrimitive = (decryptingPrimitive == null) ? createDecryptingPrimitive() : decryptingPrimitive;
Key cek = keyManagementModeAlg.manageForDecrypt(cryptoPrimitive, getEncryptedKey(), contentEncryptionKeyDesc, getHeaders(), getProviderCtx());
ContentEncryptionParts contentEncryptionParts = new ContentEncryptionParts(iv, ciphertext, getIntegrity());
byte[] aad = getEncodedHeaderAsciiBytesForAdditionalAuthenticatedData();
byte[] rawCek = cek.getEncoded();
checkCek(contentEncryptionAlg, contentEncryptionKeyDesc, rawCek);
byte[] decrypted = contentEncryptionAlg.decrypt(contentEncryptionParts, aad, rawCek, getHeaders(), getProviderCtx());
decrypted = decompress(getHeaders(), decrypted);
setPlaintext(decrypted);
}AlgorithmFactoryFactory
这里持有了所有的加密类
改造点1:我们sm3应该也添加一个自己的算法类
private void initialize()
{
String version = System.getProperty("java.version");
String vendor = System.getProperty("java.vendor");
String home = System.getProperty("java.home");
String providers = Arrays.toString(Security.getProviders());
log.debug("Initializing jose4j (running with Java {} from {} at {} with {} security providers installed)...", version, vendor, home, providers);
long startTime = System.currentTimeMillis();
jwsAlgorithmFactory = new AlgorithmFactory<>(HeaderParameterNames.ALGORITHM, JsonWebSignatureAlgorithm.class);
jwsAlgorithmFactory.registerAlgorithm(new UnsecuredNoneAlgorithm());
jwsAlgorithmFactory.registerAlgorithm(new HmacUsingShaAlgorithm.HmacSha256());
jwsAlgorithmFactory.registerAlgorithm(new HmacUsingShaAlgorithm.HmacSha384());
jwsAlgorithmFactory.registerAlgorithm(new HmacUsingShaAlgorithm.HmacSha512());
jwsAlgorithmFactory.registerAlgorithm(new EcdsaUsingShaAlgorithm.EcdsaP256UsingSha256());
jwsAlgorithmFactory.registerAlgorithm(new EcdsaUsingShaAlgorithm.EcdsaP384UsingSha384());
jwsAlgorithmFactory.registerAlgorithm(new EcdsaUsingShaAlgorithm.EcdsaP521UsingSha512());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaSha256());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaSha384());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaSha512());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaPssSha256());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaPssSha384());
jwsAlgorithmFactory.registerAlgorithm(new RsaUsingShaAlgorithm.RsaPssSha512());
log.debug("JWS signature algorithms: {}", jwsAlgorithmFactory.getSupportedAlgorithms());
jweKeyMgmtModeAlgorithmFactory = new AlgorithmFactory<>(HeaderParameterNames.ALGORITHM, KeyManagementAlgorithm.class);
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new RsaKeyManagementAlgorithm.Rsa1_5());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new RsaKeyManagementAlgorithm.RsaOaep());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new RsaKeyManagementAlgorithm.RsaOaep256());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new DirectKeyManagementAlgorithm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesKeyWrapManagementAlgorithm.Aes128());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesKeyWrapManagementAlgorithm.Aes192());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesKeyWrapManagementAlgorithm.Aes256());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new EcdhKeyAgreementAlgorithm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new EcdhKeyAgreementWithAesKeyWrapAlgorithm.EcdhKeyAgreementWithAes128KeyWrapAlgorithm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new EcdhKeyAgreementWithAesKeyWrapAlgorithm.EcdhKeyAgreementWithAes192KeyWrapAlgorithm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new EcdhKeyAgreementWithAesKeyWrapAlgorithm.EcdhKeyAgreementWithAes256KeyWrapAlgorithm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new Pbes2HmacShaWithAesKeyWrapAlgorithm.HmacSha256Aes128());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new Pbes2HmacShaWithAesKeyWrapAlgorithm.HmacSha384Aes192());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new Pbes2HmacShaWithAesKeyWrapAlgorithm.HmacSha512Aes256());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesGcmKeyEncryptionAlgorithm.Aes128Gcm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesGcmKeyEncryptionAlgorithm.Aes192Gcm());
jweKeyMgmtModeAlgorithmFactory.registerAlgorithm(new AesGcmKeyEncryptionAlgorithm.Aes256Gcm());
log.debug("JWE key management algorithms: {}", jweKeyMgmtModeAlgorithmFactory.getSupportedAlgorithms());
jweContentEncryptionAlgorithmFactory = new AlgorithmFactory<>(HeaderParameterNames.ENCRYPTION_METHOD, ContentEncryptionAlgorithm.class);
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesCbcHmacSha2ContentEncryptionAlgorithm.Aes128CbcHmacSha256());
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesCbcHmacSha2ContentEncryptionAlgorithm.Aes192CbcHmacSha384());
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesCbcHmacSha2ContentEncryptionAlgorithm.Aes256CbcHmacSha512());
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesGcmContentEncryptionAlgorithm.Aes128Gcm());
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesGcmContentEncryptionAlgorithm.Aes192Gcm());
jweContentEncryptionAlgorithmFactory.registerAlgorithm(new AesGcmContentEncryptionAlgorithm.Aes256Gcm());
log.debug("JWE content encryption algorithms: {}", jweContentEncryptionAlgorithmFactory.getSupportedAlgorithms());
compressionAlgorithmFactory = new AlgorithmFactory<>(HeaderParameterNames.ZIP, CompressionAlgorithm.class);
compressionAlgorithmFactory.registerAlgorithm(new DeflateRFC1951CompressionAlgorithm());
log.debug("JWE compression algorithms: {}", compressionAlgorithmFactory.getSupportedAlgorithms());
log.debug("Initialized jose4j in {}ms", (System.currentTimeMillis() - startTime));
}改造点2:试下一个我们自己的key
package org.jose4j.keys;
import org.jose4j.lang.ByteUtil;
import javax.crypto.spec.SecretKeySpec;
/**
*/
public class AesKey extends SecretKeySpec
{
public static final String ALGORITHM = "AES";
public AesKey(byte[] bytes)
{
super(bytes, ALGORITHM);
}
@Override
public String toString()
{
return ByteUtil.bitLength(getEncoded().length) + " bit " + ALGORITHM + " key";
}
}若有收获,就点个赞吧
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




