use of io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm in project jans by JanssenProject.
the class AuthCryptoProvider method generateKeyEncryption.
private JSONObject generateKeyEncryption(Algorithm algorithm, Long expirationTime, int keyLength) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, OperatorCreationException, CertificateException, KeyStoreException, IOException {
KeyEncryptionAlgorithm keyEncryptionAlgorithm = KeyEncryptionAlgorithm.fromName(algorithm.getParamName());
if (keyEncryptionAlgorithm == null) {
algorithm = Algorithm.RS256;
keyEncryptionAlgorithm = KeyEncryptionAlgorithm.RSA1_5;
}
KeyPairGenerator keyGen = null;
String signatureAlgorithm = null;
final AlgorithmFamily algorithmFamily = algorithm.getFamily();
switch(algorithmFamily) {
case RSA:
{
keyGen = KeyPairGenerator.getInstance(algorithmFamily.toString(), "BC");
keyGen.initialize(keyLength, new SecureRandom());
signatureAlgorithm = "SHA256WITHRSA";
break;
}
case EC:
{
ECGenParameterSpec eccgen = new ECGenParameterSpec(keyEncryptionAlgorithm.getCurve().getAlias());
keyGen = KeyPairGenerator.getInstance(algorithmFamily.toString(), "BC");
keyGen.initialize(eccgen, new SecureRandom());
signatureAlgorithm = "SHA256WITHECDSA";
break;
}
default:
{
throw new IllegalStateException("The provided key encryption algorithm parameter is not supported: algorithmFamily = " + algorithmFamily);
}
}
return getJson(algorithm, keyGen, signatureAlgorithm, expirationTime);
}
use of io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm in project jans by JanssenProject.
the class AuthCryptoProvider method getJson.
private JSONObject getJson(final Algorithm algorithm, final KeyPairGenerator keyGen, final String signatureAlgorithmStr, final Long expirationTime) throws NoSuchAlgorithmException, OperatorCreationException, CertificateException, KeyStoreException, IOException {
// Generate the key
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey pk = keyPair.getPrivate();
// Java API requires a certificate chain
X509Certificate cert = generateV3Certificate(keyPair, dnName, signatureAlgorithmStr, expirationTime);
X509Certificate[] chain = new X509Certificate[1];
chain[0] = cert;
String alias = UUID.randomUUID().toString() + getKidSuffix(algorithm.getUse(), algorithm);
keyStore.setKeyEntry(alias, pk, keyStoreSecret.toCharArray(), chain);
final String oldAliasByAlgorithm = getAliasByAlgorithmForDeletion(algorithm, alias);
if (StringUtils.isNotBlank(oldAliasByAlgorithm)) {
keyStore.deleteEntry(oldAliasByAlgorithm);
LOG.trace("New key: " + alias + ", deleted key: " + oldAliasByAlgorithm);
}
try (FileOutputStream stream = new FileOutputStream(keyStoreFile)) {
keyStore.store(stream, keyStoreSecret.toCharArray());
}
final PublicKey publicKey = keyPair.getPublic();
Use use = algorithm.getUse();
JSONObject jsonObject = new JSONObject();
jsonObject.put(JWKParameter.KEY_TYPE, algorithm.getFamily());
jsonObject.put(JWKParameter.KEY_ID, alias);
jsonObject.put(JWKParameter.KEY_USE, algorithm.getUse().getParamName());
jsonObject.put(JWKParameter.ALGORITHM, algorithm.getParamName());
jsonObject.put(JWKParameter.EXPIRATION_TIME, expirationTime);
if (publicKey instanceof RSAPublicKey) {
RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
jsonObject.put(JWKParameter.MODULUS, Base64Util.base64urlencodeUnsignedBigInt(rsaPublicKey.getModulus()));
jsonObject.put(JWKParameter.EXPONENT, Base64Util.base64urlencodeUnsignedBigInt(rsaPublicKey.getPublicExponent()));
} else if (publicKey instanceof ECPublicKey) {
ECPublicKey ecPublicKey = (ECPublicKey) publicKey;
if (use == Use.SIGNATURE) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.fromString(algorithm.getParamName());
jsonObject.put(JWKParameter.CURVE, signatureAlgorithm.getCurve().getName());
} else if (use == Use.ENCRYPTION) {
KeyEncryptionAlgorithm keyEncryptionAlgorithm = KeyEncryptionAlgorithm.fromName(algorithm.getParamName());
jsonObject.put(JWKParameter.CURVE, keyEncryptionAlgorithm.getCurve().getName());
}
jsonObject.put(JWKParameter.X, Base64Util.base64urlencodeUnsignedBigInt(ecPublicKey.getW().getAffineX()));
jsonObject.put(JWKParameter.Y, Base64Util.base64urlencodeUnsignedBigInt(ecPublicKey.getW().getAffineY()));
} else if (use == Use.SIGNATURE && publicKey instanceof EdDSAPublicKey) {
EdDSAPublicKey edDSAPublicKey = (EdDSAPublicKey) publicKey;
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.fromString(algorithm.getParamName());
jsonObject.put(JWKParameter.CURVE, signatureAlgorithm.getCurve().getName());
jsonObject.put(JWKParameter.X, Base64Util.base64urlencode(edDSAPublicKey.getEncoded()));
// EdDSA keys (EdDSAPublicKey, EDDSAPrivateKey) don't use BigInteger, but only byte[],
// so Base64Util.base64urlencode, but not Base64Util.base64urlencodeUnsignedBigInt is used.
}
JSONArray x5c = new JSONArray();
x5c.put(Base64.encodeBase64String(cert.getEncoded()));
jsonObject.put(JWKParameter.CERTIFICATE_CHAIN, x5c);
return jsonObject;
}
use of io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm in project jans by JanssenProject.
the class JweDecrypterImpl method decrypt.
@Override
public Jwe decrypt(String encryptedJwe) throws InvalidJweException {
try {
String[] jweParts = encryptedJwe.split("\\.");
if (jweParts.length != 5) {
throw new InvalidJwtException("Invalid JWS format.");
}
String encodedHeader = jweParts[0];
String encodedEncryptedKey = jweParts[1];
String encodedInitializationVector = jweParts[2];
String encodedCipherText = jweParts[3];
String encodedIntegrityValue = jweParts[4];
Jwe jwe = new Jwe();
jwe.setEncodedHeader(encodedHeader);
jwe.setEncodedEncryptedKey(encodedEncryptedKey);
jwe.setEncodedInitializationVector(encodedInitializationVector);
jwe.setEncodedCiphertext(encodedCipherText);
jwe.setEncodedIntegrityValue(encodedIntegrityValue);
jwe.setHeader(new JwtHeader(encodedHeader));
EncryptedJWT encryptedJwt = EncryptedJWT.parse(encryptedJwe);
setKeyEncryptionAlgorithm(KeyEncryptionAlgorithm.fromName(jwe.getHeader().getClaimAsString(JwtHeaderName.ALGORITHM)));
setBlockEncryptionAlgorithm(BlockEncryptionAlgorithm.fromName(jwe.getHeader().getClaimAsString(JwtHeaderName.ENCRYPTION_METHOD)));
final KeyEncryptionAlgorithm keyEncryptionAlgorithm = getKeyEncryptionAlgorithm();
Key encriptionKey = null;
if (keyEncryptionAlgorithm == KeyEncryptionAlgorithm.RSA1_5 || keyEncryptionAlgorithm == KeyEncryptionAlgorithm.RSA_OAEP) {
encriptionKey = privateKey;
} else if (keyEncryptionAlgorithm == KeyEncryptionAlgorithm.A128KW || keyEncryptionAlgorithm == KeyEncryptionAlgorithm.A256KW) {
if (sharedSymmetricKey == null) {
throw new InvalidJweException("The shared symmetric key is null");
}
int keyLength = 16;
if (keyEncryptionAlgorithm == KeyEncryptionAlgorithm.A256KW) {
keyLength = 32;
}
if (sharedSymmetricKey.length != keyLength) {
MessageDigest sha = MessageDigest.getInstance("SHA-256");
sharedSymmetricKey = sha.digest(sharedSymmetricKey);
sharedSymmetricKey = Arrays.copyOf(sharedSymmetricKey, keyLength);
}
encriptionKey = new SecretKeySpec(sharedSymmetricKey, 0, sharedSymmetricKey.length, "AES");
} else {
throw new InvalidJweException("The key encryption algorithm is not supported");
}
JWEDecrypter decrypter = DECRYPTER_FACTORY.createJWEDecrypter(encryptedJwt.getHeader(), encriptionKey);
decrypter.getJCAContext().setProvider(SecurityProviderUtility.getInstance());
encryptedJwt.decrypt(decrypter);
final SignedJWT signedJWT = encryptedJwt.getPayload().toSignedJWT();
if (signedJWT != null) {
final Jwt jwt = Jwt.parse(signedJWT.serialize());
jwe.setSignedJWTPayload(jwt);
jwe.setClaims(jwt.getClaims());
} else {
final String base64encodedPayload = encryptedJwt.getPayload().toString();
validateNestedJwt(base64encodedPayload);
jwe.setClaims(new JwtClaims(base64encodedPayload));
}
return jwe;
} catch (Exception e) {
throw new InvalidJweException(e);
}
}
use of io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm in project jans by JanssenProject.
the class JwrService method encryptJwe.
private Jwe encryptJwe(Jwe jwe, Client client) throws Exception {
if (appConfiguration.getUseNestedJwtDuringEncryption()) {
JwtSigner jwtSigner = JwtSigner.newJwtSigner(appConfiguration, webKeysConfiguration, client);
Jwt jwt = jwtSigner.newJwt();
jwt.setClaims(jwe.getClaims());
jwe.setSignedJWTPayload(signJwt(jwt, client));
}
KeyEncryptionAlgorithm keyEncryptionAlgorithm = KeyEncryptionAlgorithm.fromName(jwe.getHeader().getClaimAsString(ALGORITHM));
final BlockEncryptionAlgorithm encryptionMethod = jwe.getHeader().getEncryptionMethod();
if (keyEncryptionAlgorithm == KeyEncryptionAlgorithm.RSA_OAEP || keyEncryptionAlgorithm == KeyEncryptionAlgorithm.RSA1_5) {
JSONObject jsonWebKeys = JwtUtil.getJSONWebKeys(client.getJwksUri());
String keyId = new ServerCryptoProvider(cryptoProvider).getKeyId(JSONWebKeySet.fromJSONObject(jsonWebKeys), Algorithm.fromString(keyEncryptionAlgorithm.getName()), Use.ENCRYPTION);
PublicKey publicKey = cryptoProvider.getPublicKey(keyId, jsonWebKeys, null);
jwe.getHeader().setKeyId(keyId);
if (publicKey == null) {
throw new InvalidJweException("The public key is not valid");
}
JweEncrypter jweEncrypter = new JweEncrypterImpl(keyEncryptionAlgorithm, encryptionMethod, publicKey);
return jweEncrypter.encrypt(jwe);
}
if (keyEncryptionAlgorithm == KeyEncryptionAlgorithm.A128KW || keyEncryptionAlgorithm == KeyEncryptionAlgorithm.A256KW) {
byte[] sharedSymmetricKey = clientService.decryptSecret(client.getClientSecret()).getBytes(StandardCharsets.UTF_8);
JweEncrypter jweEncrypter = new JweEncrypterImpl(keyEncryptionAlgorithm, encryptionMethod, sharedSymmetricKey);
return jweEncrypter.encrypt(jwe);
}
throw new IllegalArgumentException("Unsupported encryption algorithm: " + keyEncryptionAlgorithm);
}
use of io.jans.as.model.crypto.encryption.KeyEncryptionAlgorithm in project jans by JanssenProject.
the class RegisterSiteOperation method createRegisterClientRequest.
private RegisterRequest createRegisterClientRequest(RegisterSiteParams params, String rpId) {
String clientName = "jans_client_api client for rp: " + rpId;
if (!Strings.isNullOrEmpty(params.getClientName())) {
clientName = params.getClientName();
}
final RegisterRequest request = new RegisterRequest(ApplicationType.WEB, clientName, params.getRedirectUris());
request.setResponseTypesStrings(params.getResponseTypes());
request.setJwksUri(params.getClientJwksUri());
request.setClaimsRedirectUris(params.getClaimsRedirectUri() != null ? params.getClaimsRedirectUri() : new ArrayList<String>());
request.setPostLogoutRedirectUris(params.getPostLogoutRedirectUris() != null ? params.getPostLogoutRedirectUris() : Lists.newArrayList());
request.setContacts(params.getContacts());
request.setScope(params.getScope());
request.setDefaultAcrValues(params.getAcrValues());
if (StringUtils.isNotBlank(params.getClientTokenEndpointAuthSigningAlg())) {
SignatureAlgorithm signatureAlgorithms = SignatureAlgorithm.fromString(params.getClientTokenEndpointAuthSigningAlg());
if (signatureAlgorithms == null) {
LOG.error("Received invalid algorithm in `client_token_endpoint_auth_signing_alg` property. Value: " + params.getClientTokenEndpointAuthSigningAlg());
throw new HttpException(ErrorResponseCode.INVALID_SIGNATURE_ALGORITHM);
}
request.setTokenEndpointAuthSigningAlg(signatureAlgorithms);
}
if (StringUtils.isNotBlank(rpId)) {
request.addCustomAttribute("rp_id", rpId);
}
List<GrantType> grantTypes = Lists.newArrayList();
for (String grantType : params.getGrantTypes()) {
grantTypes.add(GrantType.fromString(grantType));
}
request.setGrantTypes(grantTypes);
if (StringUtils.isNotBlank(params.getClientFrontchannelLogoutUri())) {
request.setFrontChannelLogoutUri(params.getClientFrontchannelLogoutUri());
}
if (StringUtils.isNotBlank(params.getClientTokenEndpointAuthMethod())) {
final AuthenticationMethod authenticationMethod = AuthenticationMethod.fromString(params.getClientTokenEndpointAuthMethod());
if (authenticationMethod != null) {
request.setTokenEndpointAuthMethod(authenticationMethod);
}
}
if (params.getClientRequestUris() != null && !params.getClientRequestUris().isEmpty()) {
request.setRequestUris(params.getClientRequestUris());
}
if (!Strings.isNullOrEmpty(params.getClientSectorIdentifierUri())) {
request.setSectorIdentifierUri(params.getClientSectorIdentifierUri());
}
request.setAccessTokenAsJwt(params.getAccessTokenAsJwt());
request.setAccessTokenSigningAlg(SignatureAlgorithm.fromString(params.getAccessTokenSigningAlg()));
request.setRptAsJwt(params.getRptAsJwt());
if (!Strings.isNullOrEmpty(params.getLogoUri())) {
request.setLogoUri(params.getLogoUri());
}
if (!Strings.isNullOrEmpty(params.getClientUri())) {
request.setClientUri(params.getClientUri());
}
if (!Strings.isNullOrEmpty(params.getPolicyUri())) {
request.setPolicyUri(params.getPolicyUri());
}
if (params.getFrontChannelLogoutSessionRequired() != null) {
request.setFrontChannelLogoutSessionRequired(params.getFrontChannelLogoutSessionRequired());
}
if (!Strings.isNullOrEmpty(params.getTosUri())) {
request.setTosUri(params.getTosUri());
}
if (!Strings.isNullOrEmpty(params.getJwks())) {
request.setJwks(params.getJwks());
}
if (!Strings.isNullOrEmpty(params.getIdTokenBindingCnf())) {
request.setIdTokenTokenBindingCnf(params.getIdTokenBindingCnf());
}
if (!Strings.isNullOrEmpty(params.getTlsClientAuthSubjectDn())) {
request.setTlsClientAuthSubjectDn(params.getTlsClientAuthSubjectDn());
}
if (!Strings.isNullOrEmpty(params.getSubjectType())) {
SubjectType subjectType = SubjectType.fromString(params.getSubjectType());
if (subjectType == null) {
LOG.error("Received invalid values in `subject_type` property. Value: " + params.getSubjectType());
throw new HttpException(ErrorResponseCode.INVALID_SUBJECT_TYPE);
}
request.setSubjectType(subjectType);
}
if (params.getRunIntrospectionScriptBeforeAccessTokenAsJwtCreationAndIncludeClaims() != null) {
request.setRunIntrospectionScriptBeforeAccessTokenAsJwtCreationAndIncludeClaims(params.getRunIntrospectionScriptBeforeAccessTokenAsJwtCreationAndIncludeClaims());
}
if (!Strings.isNullOrEmpty(params.getIdTokenSignedResponseAlg())) {
SignatureAlgorithm signatureAlgorithms = SignatureAlgorithm.fromString(params.getIdTokenSignedResponseAlg());
if (signatureAlgorithms == null) {
LOG.error("Received invalid algorithm in `id_token_signed_response_alg` property. Value: " + params.getIdTokenSignedResponseAlg());
throw new HttpException(ErrorResponseCode.INVALID_SIGNATURE_ALGORITHM);
}
if (signatureAlgorithms == SignatureAlgorithm.NONE && !getConfigurationService().getConfiguration().getAcceptIdTokenWithoutSignature()) {
LOG.error("`ID_TOKEN` without signature is not allowed. To allow `ID_TOKEN` without signature set `accept_id_token_without_signature` field to 'true' in client-api-server.yml.");
throw new HttpException(ErrorResponseCode.ID_TOKEN_WITHOUT_SIGNATURE_NOT_ALLOWED);
}
request.setIdTokenSignedResponseAlg(signatureAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getIdTokenEncryptedResponseAlg())) {
KeyEncryptionAlgorithm keyEncryptionAlgorithms = KeyEncryptionAlgorithm.fromName(params.getIdTokenEncryptedResponseAlg());
if (keyEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `id_token_encrypted_response_alg` property. Value: " + params.getIdTokenEncryptedResponseAlg());
throw new HttpException(ErrorResponseCode.INVALID_KEY_ENCRYPTION_ALGORITHM);
}
request.setIdTokenEncryptedResponseAlg(keyEncryptionAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getIdTokenEncryptedResponseEnc())) {
BlockEncryptionAlgorithm blockEncryptionAlgorithms = BlockEncryptionAlgorithm.fromName(params.getIdTokenEncryptedResponseEnc());
if (blockEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `id_token_encrypted_response_enc` property. Value: " + params.getIdTokenEncryptedResponseEnc());
throw new HttpException(ErrorResponseCode.INVALID_BLOCK_ENCRYPTION_ALGORITHM);
}
request.setIdTokenEncryptedResponseEnc(blockEncryptionAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getUserInfoSignedResponseAlg())) {
SignatureAlgorithm signatureAlgorithms = SignatureAlgorithm.fromString(params.getUserInfoSignedResponseAlg());
if (signatureAlgorithms == null) {
LOG.error("Received invalid algorithm in `user_info_signed_response_alg` property. Value: " + params.getUserInfoSignedResponseAlg());
throw new HttpException(ErrorResponseCode.INVALID_SIGNATURE_ALGORITHM);
}
request.setUserInfoSignedResponseAlg(signatureAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getUserInfoEncryptedResponseAlg())) {
KeyEncryptionAlgorithm keyEncryptionAlgorithms = KeyEncryptionAlgorithm.fromName(params.getUserInfoEncryptedResponseAlg());
if (keyEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `user_info_encrypted_response_alg` property. Value: " + params.getUserInfoEncryptedResponseAlg());
throw new HttpException(ErrorResponseCode.INVALID_KEY_ENCRYPTION_ALGORITHM);
}
request.setUserInfoEncryptedResponseAlg(keyEncryptionAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getUserInfoEncryptedResponseEnc())) {
BlockEncryptionAlgorithm blockEncryptionAlgorithms = BlockEncryptionAlgorithm.fromName(params.getUserInfoEncryptedResponseEnc());
if (blockEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `user_info_encrypted_response_enc` property. Value: " + params.getUserInfoEncryptedResponseEnc());
throw new HttpException(ErrorResponseCode.INVALID_BLOCK_ENCRYPTION_ALGORITHM);
}
request.setUserInfoEncryptedResponseEnc(blockEncryptionAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getRequestObjectSigningAlg())) {
SignatureAlgorithm signatureAlgorithms = SignatureAlgorithm.fromString(params.getRequestObjectSigningAlg());
if (signatureAlgorithms == null) {
LOG.error("Received invalid algorithm in `request_object_signing_alg` property. Value: " + params.getRequestObjectSigningAlg());
throw new HttpException(ErrorResponseCode.INVALID_SIGNATURE_ALGORITHM);
}
request.setRequestObjectSigningAlg(signatureAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getRequestObjectEncryptionAlg())) {
KeyEncryptionAlgorithm keyEncryptionAlgorithms = KeyEncryptionAlgorithm.fromName(params.getRequestObjectEncryptionAlg());
if (keyEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `request_object_encryption_alg` property. Value: " + params.getRequestObjectEncryptionAlg());
throw new HttpException(ErrorResponseCode.INVALID_KEY_ENCRYPTION_ALGORITHM);
}
request.setRequestObjectEncryptionAlg(keyEncryptionAlgorithms);
}
if (!Strings.isNullOrEmpty(params.getRequestObjectEncryptionEnc())) {
BlockEncryptionAlgorithm blockEncryptionAlgorithms = BlockEncryptionAlgorithm.fromName(params.getRequestObjectEncryptionEnc());
if (blockEncryptionAlgorithms == null) {
LOG.error("Received invalid algorithm in `request_object_encryption_enc` property. Value: " + params.getRequestObjectEncryptionEnc());
throw new HttpException(ErrorResponseCode.INVALID_BLOCK_ENCRYPTION_ALGORITHM);
}
request.setRequestObjectEncryptionEnc(blockEncryptionAlgorithms);
}
if (params.getDefaultMaxAge() != null && NumberUtils.isNumber(params.getDefaultMaxAge().toString())) {
request.setDefaultMaxAge(params.getDefaultMaxAge());
}
if (params.getRequireAuthTime() != null) {
request.setRequireAuthTime(params.getRequireAuthTime());
}
if (!Strings.isNullOrEmpty(params.getInitiateLoginUri())) {
request.setInitiateLoginUri(params.getInitiateLoginUri());
}
if (params.getAuthorizedOrigins() != null && !params.getAuthorizedOrigins().isEmpty()) {
request.setAuthorizedOrigins(params.getAuthorizedOrigins());
}
if (params.getAccessTokenLifetime() != null && NumberUtils.isNumber(params.getAccessTokenLifetime().toString())) {
request.setAccessTokenLifetime(params.getAccessTokenLifetime());
}
if (!Strings.isNullOrEmpty(params.getSoftwareId())) {
request.setSoftwareId(params.getSoftwareId());
}
if (!Strings.isNullOrEmpty(params.getSoftwareVersion())) {
request.setSoftwareVersion(params.getSoftwareVersion());
}
if (!Strings.isNullOrEmpty(params.getSoftwareStatement())) {
request.setSoftwareStatement(params.getSoftwareStatement());
}
if (params.getAllowSpontaneousScopes() != null) {
request.setAllowSpontaneousScopes(params.getAllowSpontaneousScopes());
}
if (CollectionUtils.isNotEmpty(params.getSpontaneousScopes())) {
request.setSpontaneousScopes(params.getSpontaneousScopes());
}
if (params.getCustomAttributes() != null && !params.getCustomAttributes().isEmpty()) {
params.getCustomAttributes().entrySet().removeIf(entry -> entry.getKey().contains("oxAuthTrustedClient"));
params.getCustomAttributes().entrySet().stream().forEach(e -> {
request.addCustomAttribute(e.getKey(), e.getValue());
});
}
return request;
}
Aggregations