暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

cas tgc加解密

原创 金乔 2022-03-24
735


配置

#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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论