aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas <>2021-02-08 18:47:34 +0100
committerThomas <>2021-02-08 18:47:34 +0100
commit07318e70ea3a9d25ca945c391820149183c61ca0 (patch)
treeebeb4cf8fb28cdba6cfadac41a6c74b3dfda500b
parent811165262f7ef196c8586e42b838d7d7ba376e16 (diff)
downloadNational_eIDAS_Gateway-07318e70ea3a9d25ca945c391820149183c61ca0.tar.gz
National_eIDAS_Gateway-07318e70ea3a9d25ca945c391820149183c61ca0.tar.bz2
National_eIDAS_Gateway-07318e70ea3a9d25ca945c391820149183c61ca0.zip
add Binding Public-Key into technical AuthBlock in case of an ID Austria process
-rw-r--r--connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java114
-rw-r--r--connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java5
-rw-r--r--connector/src/test/resources/data/pvp2_authn_3.xml3
-rw-r--r--connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java3
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java12
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java25
6 files changed, 116 insertions, 46 deletions
diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java
index a9eb06be..881eeb8a 100644
--- a/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java
+++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java
@@ -75,7 +75,7 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
if (nameIdPolicy != null) {
final String nameIdFormat = nameIdPolicy.getFormat();
if (nameIdFormat != null) {
- if (!(NameIDType.TRANSIENT.equals(nameIdFormat)
+ if (!(NameIDType.TRANSIENT.equals(nameIdFormat)
|| NameIDType.PERSISTENT.equals(nameIdFormat))) {
throw new NameIdFormatNotSupportedException(nameIdFormat);
@@ -114,10 +114,10 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
// post-process requested LoA comparison-level
pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode(
extractComparisonLevel(authnReq));
-
- //extract information from requested attributes
+
+ // extract information from requested attributes
extractFromRequestedAttriutes(pendingReq, authnReq);
-
+
} catch (final EaafStorageException e) {
log.info("Can NOT store Authn. Req. data into pendingRequest.", e);
throw new AuthnRequestValidatorException("internal.02", null, e);
@@ -126,14 +126,14 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
}
- private void extractFromRequestedAttriutes(IRequest pendingReq, AuthnRequest authnReq)
- throws AuthnRequestValidatorException {
+ private void extractFromRequestedAttriutes(IRequest pendingReq, AuthnRequest authnReq)
+ throws AuthnRequestValidatorException, EaafStorageException {
// validate and process requested attributes
boolean sectorDetected = false;
-
+
final ServiceProviderConfiguration spConfig = pendingReq.getServiceProviderConfiguration(
ServiceProviderConfiguration.class);
-
+
if (authnReq.getExtensions() != null) {
final List<XMLObject> requestedAttributes = authnReq.getExtensions().getUnknownXMLObjects();
for (final XMLObject reqAttrObj : requestedAttributes) {
@@ -143,77 +143,101 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
for (final EaafRequestedAttribute el : reqAttr.getAttributes()) {
log.trace("Processing req. attribute '" + el.getName() + "' ... ");
if (el.getName().equals(PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME)) {
- sectorDetected = extractBpkTargetIdentifier(el, spConfig);
-
+ sectorDetected = extractBpkTargetIdentifier(el, spConfig);
+
} else if (el.getName().equals(ExtendedPvpAttributeDefinitions.EID_TRANSACTION_ID_NAME)) {
extractUniqueTransactionId(el, pendingReq);
-
+
+ } else if (el.getName().equals(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME)) {
+ extractBindingPublicKey(el, pendingReq);
+
} else {
log.debug("Ignore req. attribute: " + el.getName());
-
+
}
}
} else {
log.debug("No requested Attributes in Authn. Request");
-
+
}
} else {
log.info("Ignore unknown requested attribute: " + reqAttrObj.getElementQName().toString());
-
+
}
}
}
-
+
if (!sectorDetected) {
log.warn("Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information.");
throw new AuthnRequestValidatorException("pvp2.22", new Object[] {
"NO or NO VALID target-sector information" });
}
-
+
+ }
+
+ private void extractBindingPublicKey(EaafRequestedAttribute el, IRequest pendingReq)
+ throws EaafStorageException {
+ if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) {
+ final String bindingPubKey = el.getAttributeValues().get(0).getDOM().getTextContent();
+ pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey);
+ log.info("Find Binding Public-Key. eIDAS authentication will be used to create an ID Austria Binding");
+
+ } else {
+ log.warn(
+ "Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute",
+ el.getName());
+
+ }
}
/**
* Extract unique transactionId from AuthnRequest.
- *
- * @param el Requested attribute from AuthnRequest
- * @param pendingReq Current pendingRequest object (has to be of type {@link RequestImpl})
- * @return <code>true</code> if transactionId extraction was successful, otherwise <code>false</code>
+ *
+ * @param el Requested attribute from AuthnRequest
+ * @param pendingReq Current pendingRequest object (has to be of type
+ * {@link RequestImpl})
+ * @return <code>true</code> if transactionId extraction was successful,
+ * otherwise <code>false</code>
*/
private boolean extractUniqueTransactionId(EaafRequestedAttribute el, IRequest pendingReq) {
if (!(pendingReq instanceof RequestImpl)) {
- log.warn("Can NOT set unique transactionId from AuthnRequest,because 'PendingRequest' is NOT from Type: {}",
+ log.warn(
+ "Can NOT set unique transactionId from AuthnRequest,because 'PendingRequest' is NOT from Type: {}",
RequestImpl.class.getName());
-
- } else {
+
+ } else {
if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) {
- final String transactionId = el.getAttributeValues().get(0).getDOM().getTextContent();
- ((RequestImpl)pendingReq).setUniqueTransactionIdentifier(transactionId);
+ final String transactionId = el.getAttributeValues().get(0).getDOM().getTextContent();
+ ((RequestImpl) pendingReq).setUniqueTransactionIdentifier(transactionId);
return true;
} else {
- log.warn("Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute",
+ log.warn(
+ "Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute",
el.getName());
-
+
}
-
+
}
-
+
return false;
}
/**
* Extract the bPK target from requested attribute.
- *
- * @param el Requested attribute from AuthnRequest
+ *
+ * @param el Requested attribute from AuthnRequest
* @param spConfig Service-Provider configuration for current process
- * @return <code>true</code> if bPK target extraction was successful, otherwise <code>false</code>
+ * @return <code>true</code> if bPK target extraction was successful, otherwise
+ * <code>false</code>
*/
- private boolean extractBpkTargetIdentifier(EaafRequestedAttribute el, ServiceProviderConfiguration spConfig) {
+ private boolean extractBpkTargetIdentifier(EaafRequestedAttribute el,
+ ServiceProviderConfiguration spConfig) {
if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) {
- final String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent();
+ final String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent();
try {
spConfig.setBpkTargetIdentifier(sectorId);
return true;
@@ -227,16 +251,16 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
log.warn("Req. attribute '" + el.getName()
+ "' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute");
}
-
+
return false;
-
+
}
-
- private void postprocessLoaLevel(IRequest pendingReq, AuthnRequest authnReq)
+
+ private void postprocessLoaLevel(IRequest pendingReq, AuthnRequest authnReq)
throws AuthnRequestValidatorException {
final List<String> reqLoA = extractLoA(authnReq);
- log.trace("SP requests LoA with: {}", String.join(", ",reqLoA));
-
+ log.trace("SP requests LoA with: {}", String.join(", ", reqLoA));
+
LevelOfAssurance minimumLoAFromConfig = LevelOfAssurance.fromString(basicConfig.getBasicConfiguration(
MsEidasNodeConstants.PROP_EIDAS_REQUEST_LOA_MINIMUM_LEVEL,
EaafConstants.EIDAS_LOA_HIGH));
@@ -246,15 +270,15 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
minimumLoAFromConfig = LevelOfAssurance.HIGH;
}
-
+
log.trace("Validate requested LoA to connector configuration minimum LoA: {} ...",
- minimumLoAFromConfig);
+ minimumLoAFromConfig);
final List<String> allowedLoA = new ArrayList<>();
for (final String loa : reqLoA) {
try {
final LevelOfAssurance intLoa = LevelOfAssurance.fromString(loa);
String selectedLoA = EaafConstants.EIDAS_LOA_HIGH;
- if (intLoa != null
+ if (intLoa != null
&& intLoa.numericValue() <= minimumLoAFromConfig.numericValue()) {
log.info("Client: {} requested LoA: {} will be upgraded to: {}",
pendingReq.getServiceProviderConfiguration().getUniqueIdentifier(),
@@ -281,7 +305,7 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA(
allowedLoA);
-
+
}
private String extractComparisonLevel(AuthnRequest authnReq) {
@@ -335,7 +359,7 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {
private String extractScopeRequsterId(AuthnRequest authnReq) {
if (authnReq.getScoping() != null) {
final Scoping scoping = authnReq.getScoping();
- if (scoping.getRequesterIDs() != null
+ if (scoping.getRequesterIDs() != null
&& scoping.getRequesterIDs().size() > 0) {
if (scoping.getRequesterIDs().size() == 1) {
return scoping.getRequesterIDs().get(0).getRequesterID();
diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java
index 9aafb4b6..c57515a0 100644
--- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java
+++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthnRequestValidatorTest.java
@@ -214,6 +214,11 @@ public class AuthnRequestValidatorTest {
Assert.assertEquals("wrong transactionId", "transId_11223344556677aabbcc",
pendingReq.getUniqueTransactionIdentifier());
+
+ Assert.assertEquals("wrong binding pubkey", "binding_pubKey_1144225247125dsfasfasdf",
+ pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, String.class));
+
+
}
diff --git a/connector/src/test/resources/data/pvp2_authn_3.xml b/connector/src/test/resources/data/pvp2_authn_3.xml
index 35e49b0f..5352c441 100644
--- a/connector/src/test/resources/data/pvp2_authn_3.xml
+++ b/connector/src/test/resources/data/pvp2_authn_3.xml
@@ -31,6 +31,9 @@
<eid:RequestedAttribute FriendlyName="transactionId" Name="urn:eidgvat:attributes.transactionId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true">
<eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">transId_11223344556677aabbcc</eid:AttributeValue>
</eid:RequestedAttribute>
+ <eid:RequestedAttribute FriendlyName="Binding-PublicKey" Name="urn:eidgvat:attributes.binding.pubkey" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true">
+ <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">binding_pubKey_1144225247125dsfasfasdf</eid:AttributeValue>
+ </eid:RequestedAttribute>
</eid:RequestedAttributes>
</saml2p:Extensions>
<saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java
index 133f104d..027d0832 100644
--- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java
+++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MsEidasNodeConstants.java
@@ -169,6 +169,9 @@ public class MsEidasNodeConstants {
public static final List<String> COUNTRY_SELECTION_PARAM_WHITELIST =
Arrays.asList(REQ_PARAM_SELECTED_COUNTRY, REQ_PARAM_SELECTED_ENVIRONMENT);
+
+ public static final String EID_BINDING_PUBLIC_KEY_NAME = "urn:eidgvat:attributes.binding.pubkey";
+
private MsEidasNodeConstants() {
//hidden Constructor for class with static values only.
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java
index 234d52dd..a2af4342 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java
@@ -18,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -81,6 +82,14 @@ public class AuthBlockSigningService {
authBlock.setTimestamp(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class));
authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier());
+
+ //set Binding PublicKey if available
+ Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME);
+ if (bindingPubKey instanceof String) {
+ authBlock.setBindingPublicKey((String) bindingPubKey);
+
+ }
+
String jwsPayload = mapper.writeValueAsString(authBlock);
log.debug("Building and sign authBlock with data: {}", jwsPayload);
@@ -172,6 +181,7 @@ public class AuthBlockSigningService {
*
*/
@Data
+ @JsonInclude(JsonInclude.Include.NON_NULL)
private static class EidasAuchBlock {
@JsonProperty("challenge")
@@ -189,6 +199,8 @@ public class AuthBlockSigningService {
@JsonProperty("piiTransactionId")
private String piiTransactionId;
+ @JsonProperty("bindingPublicKey")
+ private String bindingPublicKey;
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java
index 2e6790c5..0621081a 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java
@@ -221,6 +221,7 @@ public class CreateIdentityLinkTaskEidNewTest {
Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText());
Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty());
Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty());
+ Assert.assertFalse("binding pubKey", authBlockJson.has("bindingPublicKey"));
// check vsz request
@@ -312,9 +313,11 @@ public class CreateIdentityLinkTaskEidNewTest {
signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10));
signContentResp.getOut().add(signContentEntry);
when(szrMock, "signContent", any(), any(), any()).thenReturn(signContentResp);
-
+
String randomTestSp = RandomStringUtils.randomAlphabetic(10);
+ String bindingPubKey = RandomStringUtils.randomAlphabetic(10);
pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp);
+ pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey);
//perform test
task.execute(pendingReq, executionContext);
@@ -329,8 +332,28 @@ public class CreateIdentityLinkTaskEidNewTest {
Assert.assertNotNull("AuthProcessData", authProcessData);
Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(Constants.EIDAS_BIND, String.class));
+ // check authblock signature
String authBlock = authProcessData.getGenericDataFromSession(Constants.SZR_AUTHBLOCK, String.class);
Assert.assertNotNull("AuthBlock", authBlock);
+ final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT,
+ BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()]));
+ Pair<KeyStore, Provider> keyStore = getKeyStore();
+ X509Certificate[] trustedCerts = EaafKeyStoreUtils
+ .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond();
+ JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints);
+ Assert.assertTrue("AuthBlock not valid", result.isValid());
+ JsonNode authBlockJson = mapper.readTree(result.getPayLoad());
+ Assert.assertNotNull("deserialized AuthBlock", authBlockJson);
+
+ Assert.assertNotNull("no piiTransactionId in pendingRequesdt",
+ storedPendingReq.getUniquePiiTransactionIdentifier());
+ Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(),
+ authBlockJson.get("piiTransactionId").asText());
+ Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText());
+ Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty());
+ Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty());
+ Assert.assertTrue("binding pubKey", authBlockJson.has("bindingPublicKey"));
+ Assert.assertEquals("binding PubKey", bindingPubKey, authBlockJson.get("bindingPublicKey").asText());
Assert.assertTrue("EID process", authProcessData.isEidProcess());
Assert.assertTrue("foreigner process", authProcessData.isForeigner());