Skip to content

Commit

Permalink
allow attr defns to be encrypted
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoayyed committed May 20, 2020
1 parent 5b68a36 commit a2fd3ca
Show file tree
Hide file tree
Showing 19 changed files with 407 additions and 341 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public interface AttributeDefinition extends Serializable, Comparable<AttributeD
*/
boolean isScoped();

/**
* Indicate if the attribute value should
* be encrypted using defined public keys for the service.
*
* @return true/false
*/
boolean isEncrypted();

/**
* Gets underlying source attribute that should drive
* the value of the attribute definition.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.apereo.cas.services;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import javax.crypto.Cipher;
import java.io.Serializable;
import java.security.PublicKey;

Expand Down Expand Up @@ -33,5 +35,14 @@ public interface RegisteredServicePublicKey extends Serializable {
*
* @return the public key
*/
@JsonIgnore
PublicKey createInstance();

/**
* Convert the key into a cipher instance.
*
* @return the cipher
*/
@JsonIgnore
Cipher toCipher();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.util.CollectionUtils;
import org.apereo.cas.util.EncodingUtils;
import org.apereo.cas.util.ResourceUtils;
import org.apereo.cas.util.scripting.ExecutableCompiledGroovyScript;
import org.apereo.cas.util.scripting.GroovyShellScript;
Expand All @@ -22,9 +23,10 @@
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.jooq.lambda.Unchecked;

import javax.persistence.Transient;

import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -65,19 +67,14 @@ public class DefaultAttributeDefinition implements AttributeDefinition {

private boolean scoped;

private boolean encrypted;

private String attribute;

private String patternFormat;

private String script;

private static List<Object> formatValuesWithScope(final String scope, final List<Object> currentValues) {
return currentValues
.stream()
.map(v -> String.format("%s@%s", v, scope))
.collect(Collectors.toCollection(ArrayList::new));
}

@Override
public int compareTo(final AttributeDefinition o) {
return new CompareToBuilder()
Expand All @@ -100,10 +97,43 @@ public List<Object> resolveAttributeValues(final List<Object> attributeValues,
if (StringUtils.isNotBlank(getPatternFormat())) {
currentValues = formatValuesWithPattern(currentValues);
}
if (isEncrypted()) {
currentValues = encryptValues(currentValues, registeredService);
}
LOGGER.trace("Resolved values [{}] for attribute definition [{}]", currentValues, this);
return currentValues;
}

private static List<Object> formatValuesWithScope(final String scope, final List<Object> currentValues) {
return currentValues
.stream()
.map(v -> String.format("%s@%s", v, scope))
.collect(Collectors.toCollection(ArrayList::new));
}

private List<Object> encryptValues(final List<Object> currentValues, final RegisteredService registeredService) {
val publicKey = registeredService.getPublicKey();
if (publicKey == null) {
LOGGER.error("No public key is defined for service [{}]. No attributes will be released", registeredService);
return new ArrayList<>(0);
}
val cipher = publicKey.toCipher();
if (cipher == null) {
LOGGER.error("Unable to initialize cipher given the public key algorithm [{}]", publicKey.getAlgorithm());
return new ArrayList<>(0);
}

return currentValues
.stream()
.map(Unchecked.function(value -> {
LOGGER.trace("Encrypting attribute value [{}]", value);
val result = EncodingUtils.encodeBase64(cipher.doFinal(value.toString().getBytes(StandardCharsets.UTF_8)));
LOGGER.trace("Encrypted attribute value [{}]", result);
return result;
}))
.collect(Collectors.toCollection(ArrayList::new));
}

private List<Object> formatValuesWithPattern(final List<Object> currentValues) {
return currentValues
.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import org.apereo.cas.authentication.adaptive.intel.BlackDotIPAddressIntelligenceServiceTests;
import org.apereo.cas.authentication.adaptive.intel.GroovyIPAddressIntelligenceServiceTests;
import org.apereo.cas.authentication.adaptive.intel.RestfulIPAddressIntelligenceServiceTests;
import org.apereo.cas.authentication.attribute.DefaultAttributeDefinitionStoreTests;
import org.apereo.cas.authentication.handler.ByCredentialSourceAuthenticationHandlerResolverTests;
import org.apereo.cas.authentication.handler.ByCredentialTypeAuthenticationHandlerResolverTests;
import org.apereo.cas.authentication.policy.GroovyScriptAuthenticationPolicyTests;
Expand Down Expand Up @@ -38,7 +37,6 @@
PrincipalNameTransformerUtilsTests.class,
AuthenticationCredentialTypeMetaDataPopulatorTests.class,
DefaultPrincipalFactoryTests.class,
DefaultAttributeDefinitionStoreTests.class,
GroovyAuthenticationPreProcessorTests.class,
GroovyPrincipalFactoryTests.class,
GroovyPasswordEncoderTests.class,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jooq.lambda.Unchecked;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.Security;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -58,31 +56,6 @@ public Map<String, List<Object>> getAttributesInternal(final Principal principal
return authorizeReleaseOfAllowedAttributes(principal, attrs, registeredService, selectedService);
}

/**
* Initialize cipher based on service public key.
*
* @param publicKey the public key
* @param registeredService the registered service
* @return the false if no public key is found
* or if cipher cannot be initialized, etc.
*/
private static Cipher initializeCipherBasedOnServicePublicKey(final PublicKey publicKey,
final RegisteredService registeredService) {
try {
LOGGER.debug("Using service [{}] public key [{}] to initialize the cipher", registeredService.getServiceId(),
registeredService.getPublicKey());

val cipher = Cipher.getInstance(publicKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
LOGGER.trace("Initialized cipher in encrypt-mode via the public key algorithm [{}] for service [{}]",
publicKey.getAlgorithm(), registeredService.getServiceId());
return cipher;
} catch (final Exception e) {
LOGGER.warn("Cipher could not be initialized for service [{}]. Error [{}]",
registeredService, e.getMessage());
}
return null;
}

/**
* Authorize release of allowed attributes map.
Expand All @@ -97,22 +70,17 @@ protected Map<String, List<Object>> authorizeReleaseOfAllowedAttributes(final Pr
final Map<String, List<Object>> attrs,
final RegisteredService registeredService,
final Service selectedService) {
if (registeredService.getPublicKey() == null) {
LOGGER.error("No public key is defined for service [{}]. No attributes will be released", registeredService);
return new HashMap<>(0);
}
val publicKey = registeredService.getPublicKey().createInstance();
val publicKey = registeredService.getPublicKey();
if (publicKey == null) {
LOGGER.error("No public key can be created for service [{}]. No attributes will be released", registeredService);
LOGGER.error("No public key is defined for service [{}]. No attributes will be released", registeredService);
return new HashMap<>(0);
}

val cipher = initializeCipherBasedOnServicePublicKey(publicKey, registeredService);
LOGGER.debug("Using service [{}] public key [{}] to initialize the cipher", registeredService.getServiceId(), publicKey);
val cipher = publicKey.toCipher();
if (cipher == null) {
LOGGER.error("Unable to initialize cipher given the public key algorithm [{}]", publicKey.getAlgorithm());
return new HashMap<>(0);
}

val resolvedAttributes = new TreeMap<String, List<Object>>(String.CASE_INSENSITIVE_ORDER);
resolvedAttributes.putAll(attrs);
val attributesToRelease = new HashMap<String, List<Object>>();
Expand Down
Loading

0 comments on commit a2fd3ca

Please sign in to comment.