aboutsummaryrefslogtreecommitdiff
path: root/id/server/modules/moa-id-module-ssoTransfer
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/modules/moa-id-module-ssoTransfer')
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/pom.xml5
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/SSOTransferConstants.java11
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferAuthenticationData.java11
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferOnlineApplication.java19
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferServlet.java124
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferSignalServlet.java10
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/InitializeRestoreSSOSessionTask.java47
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java223
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/GUIUtils.java164
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/SSOContainerUtils.java118
-rw-r--r--id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java17
11 files changed, 459 insertions, 290 deletions
diff --git a/id/server/modules/moa-id-module-ssoTransfer/pom.xml b/id/server/modules/moa-id-module-ssoTransfer/pom.xml
index 8207fc502..b15d7dc85 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/pom.xml
+++ b/id/server/modules/moa-id-module-ssoTransfer/pom.xml
@@ -46,6 +46,11 @@
<version>1.52</version>
</dependency>
+ <dependency>
+ <groupId>MOA.id.server</groupId>
+ <artifactId>moa-id-frontend-resources</artifactId>
+ </dependency>
+
</dependencies>
</project> \ No newline at end of file
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/SSOTransferConstants.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/SSOTransferConstants.java
index ce3a7856b..1a4356653 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/SSOTransferConstants.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/SSOTransferConstants.java
@@ -58,8 +58,19 @@ public class SSOTransferConstants {
public static final String SSOCONTAINER_KEY_USERID = "userID";
public static final String SSOCONTAINER_KEY_SESSION = "session";
public static final String SSOCONTAINER_KEY_RESULTENDPOINT = "resultEndPoint";
+ public static final String SSOCONTAINER_KEY_NONCE = "nonce";
+ public static final String SSOCONTAINER_KEY_BLOB = "blob";
+ public static final String SSOCONTAINER_KEY_SIGNATURE = "signature";
+ public static final String SSOCONTAINER_KEY_UNIQUEUSERID = "bPK";
+
+ public static final String SSOCONTAINER_KEY_STATUS = "status";
public static final String FLAG_SSO_SESSION_RESTORED = "ssoRestoredFlag";
public static final long CERT_VALIDITY = 700; //2 years
+
+ public static final String PENDINGREQ_DH = "dhparams";
+ public static final String PENDINGREQ_NONCE = "nonce";
+
+
}
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferAuthenticationData.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferAuthenticationData.java
index 103a03063..78cbd788d 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferAuthenticationData.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferAuthenticationData.java
@@ -28,11 +28,11 @@ import java.util.List;
import org.w3c.dom.Element;
-import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.data.IdentityLink;
-import at.gv.egovernment.moa.id.config.ConfigurationException;
-import at.gv.egovernment.moa.id.config.auth.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException;
import at.gv.egovernment.moa.id.data.AuthenticationRole;
import at.gv.egovernment.moa.id.data.IAuthData;
import at.gv.egovernment.moa.id.data.MISMandate;
@@ -49,8 +49,9 @@ public class SSOTransferAuthenticationData implements IAuthData {
public SSOTransferAuthenticationData(AuthConfiguration authConfig, AuthenticationSession authSession) throws ConfigurationException {
this.authSession = authSession;
- String domainIdentifier = authConfig.getSSOTagetIdentifier().trim();
- isIDPPrivateService = domainIdentifier.startsWith(MOAIDAuthConstants.PREFIX_WPBK);
+ String domainIdentifier = authConfig.getSSOTagetIdentifier();
+ if (domainIdentifier != null)
+ isIDPPrivateService = domainIdentifier.startsWith(MOAIDAuthConstants.PREFIX_WPBK);
}
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferOnlineApplication.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferOnlineApplication.java
index 4ba2e1a01..af180ff10 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferOnlineApplication.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/data/SSOTransferOnlineApplication.java
@@ -27,11 +27,11 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
-import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters;
-import at.gv.egovernment.moa.id.config.auth.data.SAML1ConfigurationParameters;
-import at.gv.egovernment.moa.id.config.stork.CPEPS;
-import at.gv.egovernment.moa.id.config.stork.StorkAttribute;
-import at.gv.egovernment.moa.id.config.stork.StorkAttributeProviderPlugin;
+import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
+import at.gv.egovernment.moa.id.commons.api.data.CPEPS;
+import at.gv.egovernment.moa.id.commons.api.data.SAML1ConfigurationParameters;
+import at.gv.egovernment.moa.id.commons.api.data.StorkAttribute;
+import at.gv.egovernment.moa.id.commons.api.data.StorkAttributeProviderPlugin;
/**
* @author tlenz
@@ -262,15 +262,6 @@ public class SSOTransferOnlineApplication implements IOAAuthParameters {
}
/* (non-Javadoc)
- * @see at.gv.egovernment.moa.id.config.auth.IOAAuthParameters#getFormCustomizaten()
- */
- @Override
- public Map<String, String> getFormCustomizaten() {
- // TODO Auto-generated method stub
- return null;
- }
-
- /* (non-Javadoc)
* @see at.gv.egovernment.moa.id.config.auth.IOAAuthParameters#getQaaLevel()
*/
@Override
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferServlet.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferServlet.java
index 48ef5b526..b18425839 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferServlet.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferServlet.java
@@ -30,13 +30,9 @@ import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.URL;
import java.security.InvalidKeyException;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
-import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
@@ -46,17 +42,14 @@ import java.util.Date;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyAgreement;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
-import javax.crypto.spec.SecretKeySpec;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.velocity.VelocityContext;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
@@ -80,17 +73,18 @@ import com.google.gson.JsonParser;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
-import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.exception.ParseException;
-import at.gv.egovernment.moa.id.auth.exception.SessionDataStorageException;
+import at.gv.egovernment.moa.id.auth.frontend.builder.DefaultGUIFormBuilderConfiguration;
+import at.gv.egovernment.moa.id.auth.frontend.builder.IGUIFormBuilder;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.Pair;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.SSOTransferContainer;
-import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.GUIUtils;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.SSOContainerUtils;
import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.id.commons.api.exceptions.SessionDataStorageException;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
-import at.gv.egovernment.moa.id.config.auth.AuthConfiguration;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
import at.gv.egovernment.moa.id.moduls.SSOManager;
import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException;
@@ -124,6 +118,7 @@ public class SSOTransferServlet{
@Autowired ITransactionStorage transactionStorage;
@Autowired IDPCredentialProvider idpCredentials;
@Autowired AuthConfiguration authConfig;
+ @Autowired IGUIFormBuilder guiBuilder;
public SSOTransferServlet() {
super();
@@ -145,8 +140,6 @@ public class SSOTransferServlet{
method = {RequestMethod.GET})
public void testTransferSSOSessionGUIWithoutAuthentication(HttpServletRequest req, HttpServletResponse resp) throws IOException {
try {
- VelocityContext context = new VelocityContext();
-
//create first step of SSO Transfer GUI
String authURL = HTTPUtils.extractAuthURLFromRequest(req);
if (!AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix().contains(authURL)) {
@@ -155,8 +148,13 @@ public class SSOTransferServlet{
}
+ DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration(
+ authURL,
+ DefaultGUIFormBuilderConfiguration.VIEW_SSO_SESSION_TRANSFER,
+ null);
+
internalCreateQRCodeForTransfer(resp, authURL,
- "123456", "/TestTransmitSSOSession", context);
+ "123456", "/TestTransmitSSOSession", config);
} catch (MOAIDException | MOADatabaseException e) {
e.printStackTrace();
@@ -280,7 +278,7 @@ public class SSOTransferServlet{
@RequestMapping(value = { "/TransmitSSOSession"
},
- method = {RequestMethod.GET})
+ method = {RequestMethod.GET, RequestMethod.POST})
public void transferToPhone(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Logger.debug("Receive " + this.getClass().getName() + " request");
@@ -388,28 +386,32 @@ public class SSOTransferServlet{
//search SSO session
String ssoid = ssomanager.getSSOSessionID(req);
- VelocityContext context = new VelocityContext();
-
try {
+ String authURL = HTTPUtils.extractAuthURLFromRequest(req);
+ if (!AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix().
+ contains(authURL)) {
+ Logger.warn("Requested URL is not allowed.");;
+ resp.sendError(500, "Requested URL is not allowed.");
+
+ }
+
+ DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration(
+ authURL,
+ DefaultGUIFormBuilderConfiguration.VIEW_SSO_SESSION_TRANSFER,
+ null);
+
if (ssomanager.isValidSSOSession(ssoid, null)) {
//Object createQRObj = req.getParameter(SSOTransferConstants.REQ_PARAM_GENERATE_QR);
//create first step of SSO Transfer GUI
- String authURL = HTTPUtils.extractAuthURLFromRequest(req);
- if (!AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix().
- contains(authURL)) {
- Logger.warn("Requested URL is not allowed.");;
- resp.sendError(500, "Requested URL is not allowed.");
-
- }
-
+
String moaSessionID = authenticationSessionStorage.getMOASessionSSOID(ssoid);
if (MiscUtil.isNotEmpty(moaSessionID)) {
AuthenticationSession authSession = authenticationSessionStorage.getSession(moaSessionID);
if(authSession != null) {
internalCreateQRCodeForTransfer(resp, authURL,
authSession.getSessionID(),
- SSOTransferConstants.SERVLET_SSOTRANSFER_TO_SMARTPHONE, context);
+ SSOTransferConstants.SERVLET_SSOTRANSFER_TO_SMARTPHONE, config);
return;
}
@@ -417,9 +419,10 @@ public class SSOTransferServlet{
}
- context.put("errorMsg",
+ config.putCustomParameter("errorMsg",
"No active Single Sign-On session found! SSO Session transfer is not possible.");
- GUIUtils.printSSOTransferGUI(context, resp);
+
+ guiBuilder.build(resp, config, "SSO-Transfer-Module");
} catch (MOAIDException | MOADatabaseException e) {
e.printStackTrace();
@@ -458,7 +461,7 @@ public class SSOTransferServlet{
DHPublicKeySpec mobilePubKeySpec = new DHPublicKeySpec(mobilePubKey,
container.getDhParams().getF().getP(),
container.getDhParams().getF().getG());
- byte[] sharedSecret = getSecret(mobilePubKeySpec, container.getDhParams().getS());
+ byte[] sharedSecret = ssoTransferUtils.getSecret(mobilePubKeySpec, container.getDhParams().getS());
//build ASE256 key
MessageDigest digest = MessageDigest.getInstance("SHA-256");
@@ -470,7 +473,7 @@ public class SSOTransferServlet{
byte[] encryptedCSR = Base64Utils.decode(mobileCSRBase64, true);
Logger.debug("EncCSR:" + Base64Utils.encode(encryptedCSR) + " | Key:" + Base64Utils.encode(hashedSecret));
- byte[] decryptedCSR = enOrDeCryptCSR(encryptedCSR, hashedSecret, Cipher.DECRYPT_MODE);
+ byte[] decryptedCSR = ssoTransferUtils.enOrDeCryptCSR(encryptedCSR, hashedSecret, Cipher.DECRYPT_MODE);
Logger.debug("DecCSR:" + Base64Utils.encode(decryptedCSR));
Logger.debug("CSR decryption finished. --> Starting CSR validation and signing ...");
@@ -487,25 +490,23 @@ public class SSOTransferServlet{
Date now = new Date();
String personInformationToTransfer =
ssoTransferUtils.generateSignedAndEncryptedSSOContainer(
- container.getAuthURL(), moaSession, now);
+ container.getAuthURL(), moaSession, now, hashedSecret);
Logger.debug("PersonData:" + personInformationToTransfer);
//encrypt personal information
Logger.debug("PersonData generation finished. --> Starting personData encryption ... ");
- byte[] encPersonData = enOrDeCryptCSR(personInformationToTransfer.getBytes(), hashedSecret, Cipher.ENCRYPT_MODE);
- String encAndEncodedPersonalData = Base64Utils.encode(encPersonData);
Logger.debug("Encrypt personData finished. --> Send token to device.");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = new PrintWriter(resp.getOutputStream());
- out.print(encAndEncodedPersonalData);
+ out.print(personInformationToTransfer);
out.flush();
return;
}
private void internalCreateQRCodeForTransfer(HttpServletResponse resp, String authURL,
- String moaSessionID, String servletEndPoint, VelocityContext context) throws Exception {
+ String moaSessionID, String servletEndPoint, DefaultGUIFormBuilderConfiguration config) throws Exception {
SSOTransferContainer container = new SSOTransferContainer();
String token = Random.nextRandom();
@@ -530,7 +531,7 @@ public class SSOTransferServlet{
BigInteger generator = new BigInteger(Base64Utils.decode(SSOTransferConstants.DH_GENERATOR_BASE64, false));
DHParameterSpec dhSpec = new DHParameterSpec(prime, generator, 1024);
- Pair<DHPublicKeySpec, PrivateKey> dhKeyIDP = createSpecificKey(dhSpec.getP(), dhSpec.getG());
+ Pair<DHPublicKeySpec, PrivateKey> dhKeyIDP = ssoTransferUtils.createSpecificKey(dhSpec.getP(), dhSpec.getG());
container.setDhParams(dhKeyIDP);
//store container
@@ -558,25 +559,15 @@ public class SSOTransferServlet{
ByteArrayOutputStream qrStream =
QRCode.from(qrResult.toString()).to(ImageType.GIF).withSize(350, 350).stream();
String base64EncodedImage = Base64Utils.encode(qrStream.toByteArray());
- context.put("QRImage", base64EncodedImage);
+ config.putCustomParameter("QRImage", base64EncodedImage);
- context.put("successMsg", "Scan the QR-Code with your <i>SSO-Transfer App</i> to start the transfer operation.");
+ config.putCustomParameter("successMsg", "Scan the QR-Code with your <i>SSO-Transfer App</i> to start the transfer operation.");
- GUIUtils.printSSOTransferGUI(context, resp);
-
+
+ guiBuilder.build(resp, config, "SSO-Session Transfer-Module");
}
-
- public byte[] enOrDeCryptCSR(byte[] binBlob, byte[] binSecret, int mode) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
- byte[] decrypted = null;
- SecretKeySpec skeySpec = new SecretKeySpec(binSecret, "AES");
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(mode, skeySpec);
- decrypted = cipher.doFinal(binBlob);
-
- return decrypted;
- }
-
+
private X509Certificate signCSRWithMOAKey(byte[] inputCSR) throws IOException, OperatorCreationException, PKCSException, CredentialsNotAvailableException, CertificateException {
PKCS10CertificationRequest csr = new PKCS10CertificationRequest(inputCSR);
@@ -604,20 +595,7 @@ public class SSOTransferServlet{
}
-
- private static byte[] getSecret(DHPublicKeySpec kspectrans, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
- KeyAgreement aKeyAgree = KeyAgreement.getInstance("DiffieHellman");
- aKeyAgree.init(privateKey);
-
- KeyFactory kfactory = KeyFactory.getInstance("DiffieHellman");
- PublicKey pub = kfactory.generatePublic(kspectrans);
- aKeyAgree.doPhase(pub, true);
-
- byte[] secretKey = aKeyAgree.generateSecret();
- return secretKey;
-
- }
-
+
private JsonObject getJSONObjectFromPostMessage(HttpServletRequest req, boolean developmentMode) {
//read POST request
StringBuffer sb = new StringBuffer();
@@ -653,20 +631,4 @@ public class SSOTransferServlet{
}
- private Pair<DHPublicKeySpec, PrivateKey> createSpecificKey(BigInteger p, BigInteger g) throws Exception {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("DiffieHellman");
-
- DHParameterSpec param = new DHParameterSpec(p, g);
- kpg.initialize(param);
- KeyPair kp = kpg.generateKeyPair();
-
- KeyFactory kfactory = KeyFactory.getInstance("DiffieHellman");
-
- Pair<DHPublicKeySpec, PrivateKey> pair = new Pair<DHPublicKeySpec, PrivateKey>(
- (DHPublicKeySpec) kfactory.getKeySpec(kp.getPublic(), DHPublicKeySpec.class), kp.getPrivate());
- return pair;
-
- }
-
-
}
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferSignalServlet.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferSignalServlet.java
index 0b3bd892a..e92925dfb 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferSignalServlet.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/servlet/SSOTransferSignalServlet.java
@@ -33,9 +33,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils;
-import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.servlet.AbstractProcessEngineSignalController;
-import at.gv.egovernment.moa.id.moduls.IRequest;
+import at.gv.egovernment.moa.id.commons.api.IRequest;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.logging.Logger;
/**
@@ -61,13 +61,13 @@ public class SSOTransferSignalServlet extends AbstractProcessEngineSignalControl
@Override
protected void signalProcessManagement(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String pendingRequestID = StringEscapeUtils.escapeHtml(getPendingRequestId(req));
-
+ IRequest pendingReq = null;
try {
if (pendingRequestID == null) {
throw new IllegalStateException("Unable to determine MOA pending-request id.");
}
- IRequest pendingReq = requestStorage.getPendingRequest(pendingRequestID);
+ pendingReq = requestStorage.getPendingRequest(pendingRequestID);
if (pendingReq == null) {
Logger.info("No PendingRequest with Id: " + pendingRequestID + " Maybe, a transaction timeout occure.");
throw new MOAIDException("auth.28", new Object[]{pendingRequestID});
@@ -87,7 +87,7 @@ public class SSOTransferSignalServlet extends AbstractProcessEngineSignalControl
processEngine.signal(pendingReq);
} catch (Exception ex) {
- handleError(null, ex, req, resp, pendingRequestID);
+ handleError(null, ex, req, resp, pendingReq);
} finally {
//MOASessionDBUtils.closeSession();
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/InitializeRestoreSSOSessionTask.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/InitializeRestoreSSOSessionTask.java
index e84c60ec5..be27de9a1 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/InitializeRestoreSSOSessionTask.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/InitializeRestoreSSOSessionTask.java
@@ -22,21 +22,32 @@
*/
package at.gv.egovernment.moa.id.auth.modules.ssotransfer.task;
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.velocity.VelocityContext;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
-import at.gv.egovernment.moa.id.auth.exception.WrongParametersException;
+import at.gv.egovernment.moa.id.auth.frontend.builder.IGUIFormBuilder;
import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask;
import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.Pair;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.SSOTransferContainer;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.GUIUtils;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.SSOContainerUtils;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
import at.gv.egovernment.moa.id.process.api.ExecutionContext;
import at.gv.egovernment.moa.id.util.HTTPUtils;
+import at.gv.egovernment.moa.id.util.Random;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.Base64Utils;
/**
* @author tlenz
@@ -45,6 +56,9 @@ import at.gv.egovernment.moa.logging.Logger;
@Component("InitializeRestoreSSOSessionTask")
public class InitializeRestoreSSOSessionTask extends AbstractAuthServletTask {
+ @Autowired IGUIFormBuilder guiBuilder;
+ @Autowired SSOContainerUtils ssoTransferUtils;
+
/* (non-Javadoc)
* @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@@ -62,12 +76,31 @@ public class InitializeRestoreSSOSessionTask extends AbstractAuthServletTask {
response.sendError(500, "Requested URL is not allowed.");
}
-
- VelocityContext context = GUIUtils.buildSSOTransferGUI(authURL, pendingReq.getRequestID());
- GUIUtils.printSSOTransferGUI(context, response);
+
+ //use predefined parameters
+ BigInteger prime = new BigInteger(Base64Utils.decode(SSOTransferConstants.DH_PRIME_BASE64, false));
+ BigInteger generator = new BigInteger(Base64Utils.decode(SSOTransferConstants.DH_GENERATOR_BASE64, false));
+ DHParameterSpec dhSpec = new DHParameterSpec(prime, generator, 1024);
+
+ Pair<DHPublicKeySpec, PrivateKey> dhKeyIDP = ssoTransferUtils.createSpecificKey(dhSpec.getP(), dhSpec.getG());
+ String nonce = Random.nextLongRandom();
+
+ GUIUtils.buildSSOTransferGUI(guiBuilder, response, authURL,
+ pendingReq.getRequestID(), nonce, dhKeyIDP.getF());
+ //store DH params and nonce to pending-request
+ SSOTransferContainer container = new SSOTransferContainer();
+ container.setDhParams(dhKeyIDP);
+ pendingReq.setGenericDataToSession(SSOTransferConstants.PENDINGREQ_DH, container);
+ pendingReq.setGenericDataToSession(SSOTransferConstants.PENDINGREQ_NONCE, nonce);
+
+ //store pending-request
+ requestStoreage.storePendingRequest(pendingReq);
- } catch (WrongParametersException | AuthenticationException e) {
+ //set flag
+ executionContext.put("sessionRestoreFinished", false);
+
+ } catch (MOAIDException e) {
throw new TaskExecutionException(pendingReq, e.getMessage(), e);
} catch (Exception e) {
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java
index d52e03c09..003ce8c21 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/task/RestoreSSOSessionTask.java
@@ -24,33 +24,43 @@ package at.gv.egovernment.moa.id.auth.modules.ssotransfer.task;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import javax.crypto.Cipher;
+import javax.crypto.spec.DHPublicKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.BooleanUtils;
-import org.apache.velocity.VelocityContext;
import org.joda.time.DateTime;
import org.opensaml.saml2.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import com.google.common.net.MediaType;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.auth.frontend.builder.IGUIFormBuilder;
import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask;
import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.SSOTransferContainer;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.GUIUtils;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils.SSOContainerUtils;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
import at.gv.egovernment.moa.id.process.api.ExecutionContext;
-import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
+import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
+import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AssertionAttributeExtractor;
import at.gv.egovernment.moa.id.util.HTTPUtils;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.Base64Utils;
import at.gv.egovernment.moa.util.MiscUtil;
+import iaik.x509.X509Certificate;
/**
* @author tlenz
@@ -60,6 +70,7 @@ import at.gv.egovernment.moa.util.MiscUtil;
public class RestoreSSOSessionTask extends AbstractAuthServletTask {
@Autowired SSOContainerUtils ssoTransferUtils;
+ @Autowired IGUIFormBuilder guiBuilder;
/* (non-Javadoc)
* @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
@@ -87,65 +98,155 @@ public class RestoreSSOSessionTask extends AbstractAuthServletTask {
Logger.warn("Received POST-message produce an ERROR.", e);
}
-
- //session is valid --> load MOASession object
- try {
- defaultTaskInitialization(request, executionContext);
-
- } catch (MOAIDException | MOADatabaseException e1) {
- Logger.error("Database Error! MOASession is not stored!");
- throw new TaskExecutionException(pendingReq, "Load MOASession FAILED.", e1);
-
- }
-
+
+ String nonce = pendingReq.getGenericData(SSOTransferConstants.PENDINGREQ_NONCE, String.class);
+ SSOTransferContainer container = pendingReq.getGenericData(
+ SSOTransferConstants.PENDINGREQ_DH, SSOTransferContainer.class);
+ if (container == null) {
+ throw new TaskExecutionException(pendingReq, "NO DH-Params in pending-request",
+ new MOAIDException("NO DH-Params in pending-request", null));
+
+ }
+
if (MiscUtil.isNotEmpty(receivedPostMessage)) {
Logger.debug("Receive POST-Message data. Start data-validation process ... ");
+ JsonObject responseMsg = new JsonObject();
try {
+ Logger.debug("Unformated Msg:" + receivedPostMessage);
+
JsonParser parser = new JsonParser();
- JsonObject reveivedData = (JsonObject) parser.parse(sb.toString());
- JsonObject reveivedSession = reveivedData.get("session").getAsJsonObject();
- String validTo = reveivedSession.get("validTo").getAsString();
- String entityID = reveivedSession.get("entityID").getAsString();
- String sessionBlob = reveivedSession.get("sessionBlob").getAsString();
+ JsonObject receivedData = (JsonObject) parser.parse(sb.toString());
- Logger.trace("Blob:" + sessionBlob +
- " | validTo:" + validTo +
- " | entityIS:" + entityID);
+ JsonObject receivedSession = receivedData.get(
+ SSOTransferConstants.SSOCONTAINER_KEY_SESSION).getAsJsonObject();
- if (PVPConfiguration.getInstance().getIDPPublicPath().contains(entityID)) {
- // stored SSO session data is from this IDP - start local session reconstruction
- Response ssoInformation = ssoTransferUtils.validateReceivedSSOContainer(sessionBlob, entityID);
-
- //transfer SSO Assertion into MOA-Session
- ssoTransferUtils.parseSSOContainerToMOASessionDataObject(pendingReq, moasession, ssoInformation);
-
- // store MOASession into database
- try {
- authenticatedSessionStorage.storeSession(moasession);
-
- } catch (MOADatabaseException e) {
- Logger.error("Database Error! MOASession is not stored!");
- throw new MOAIDException("init.04", new Object[] {
- moasession.getSessionID()});
- }
-
- executionContext.put(SSOTransferConstants.FLAG_SSO_SESSION_RESTORED, true);
- executionContext.put("sessionRestoreFinished", false);
-
- } else {
- Logger.info("Received SSO session-data is from IDP: " + entityID
- + ". Start inderfederation process to restore SSO session ... ");
- //change to inderfederated session reconstruction
-
- Logger.warn("Device Session Transfer with interfederation is not implemented, yet!!!!");
+ Logger.debug("Received Session-Object:"+ receivedSession.toString());
+
+ String signature = receivedData.get(
+ SSOTransferConstants.SSOCONTAINER_KEY_SIGNATURE).getAsString();
+ String mobilePubKeyBase64 = receivedData.get(
+ SSOTransferConstants.SSOCONTAINER_KEY_DH_PUBKEY).getAsString();
+
+ String respNonce = receivedSession.get(
+ SSOTransferConstants.PENDINGREQ_NONCE).getAsString();
+ String encSessionBlobBase64 = receivedSession.get(
+ SSOTransferConstants.SSOCONTAINER_KEY_BLOB).getAsString();
+
+ Logger.debug("Receive PubKey:" +mobilePubKeyBase64
+ + " | SessionBlob:" + encSessionBlobBase64
+ + " | Nonce:" + respNonce
+ + " | Signature:" + signature
+ + " | SignedData:" + receivedSession.toString());
+
+ if (MiscUtil.isEmpty(respNonce) || !respNonce.equals(nonce)) {
+ Logger.warn("Received 'nonce':" + respNonce
+ + " does not match to stored 'nonce':" + nonce);
+ throw new TaskExecutionException(pendingReq, "Received 'nonce':" + respNonce
+ + " does not match to stored 'nonce':" + nonce,
+ new MOAIDException("Received 'nonce':" + respNonce + " does not match to stored 'nonce':" + nonce, null));
+
+ }
+
+
+ //finish DH key agreement
+ BigInteger mobilePubKey = new BigInteger(Base64Utils.decode(mobilePubKeyBase64, true));
+ DHPublicKeySpec mobilePubKeySpec = new DHPublicKeySpec(mobilePubKey,
+ container.getDhParams().getF().getP(),
+ container.getDhParams().getF().getG());
+ byte[] sharedSecret = ssoTransferUtils.getSecret(mobilePubKeySpec, container.getDhParams().getS());
+
+ //build ASE256 key
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ digest.reset();
+ byte[] hashedSecret = digest.digest(sharedSecret);
+
+ //decrypt CSR
+ Logger.debug("Finished Diffie-Hellman key exchange. --> Starting SessionBlob decryption ...");
+ byte[] encryptedSessionBlob = Base64Utils.decode(encSessionBlobBase64, true);
+ Logger.debug("EncSessionBlob:" + Base64Utils.encode(encryptedSessionBlob) + " | Key:" + Base64Utils.encode(hashedSecret));
+
+ byte[] sessionBlobArray = ssoTransferUtils.enOrDeCryptCSR(encryptedSessionBlob, hashedSecret, Cipher.DECRYPT_MODE);
+ String sessionBlob = new String(sessionBlobArray, "UTF-8");
+ Logger.debug("DecSessionBlob:" + sessionBlob);
+
+ //parse SAML2 assertion
+ Response ssoInformation = ssoTransferUtils.validateReceivedSSOContainer(sessionBlob);
+
+ //validate signature
+ AssertionAttributeExtractor attributeExtractor = new AssertionAttributeExtractor(ssoInformation);
+ String holderOfKeyCertBase64 = attributeExtractor.getSingleAttributeValue(PVPConstants.PVP_HOLDEROFKEY_NAME);
+ byte[] holderOfKeyCertEncoded = Base64Utils.decode(holderOfKeyCertBase64, false);
+ X509Certificate holderOfKeyCert = new X509Certificate(holderOfKeyCertEncoded);
+ Logger.debug("Found HolderOfKey Certificate:" + holderOfKeyCert.getSubjectDN().toString());
+
+
+ //TODO: implement Signature validation
+
+ Logger.debug("MobileDevice is valid. --> Starting session reconstruction ...");
+
+
+ //session is valid --> load MOASession object
+ try {
+ defaultTaskInitialization(request, executionContext);
+
+ } catch (MOAIDException | MOADatabaseException e1) {
+ Logger.error("Database Error! MOASession is not stored!");
+ throw new TaskExecutionException(pendingReq, "Load MOASession FAILED.", e1);
+
+ }
+
+ //transfer SSO Assertion into MOA-Session
+ ssoTransferUtils.parseSSOContainerToMOASessionDataObject(pendingReq, moasession, attributeExtractor);
+
+ // store MOASession into database
+ try {
+ authenticatedSessionStorage.storeSession(moasession);
+
+ } catch (MOADatabaseException e) {
+ Logger.error("Database Error! MOASession is not stored!");
+ throw new MOAIDException("init.04", new Object[] {
+ moasession.getSessionID()});
+ }
+
+ executionContext.put(SSOTransferConstants.FLAG_SSO_SESSION_RESTORED, true);
+ executionContext.put("sessionRestoreFinished", false);
+
+
+ responseMsg.addProperty(
+ SSOTransferConstants.SSOCONTAINER_KEY_STATUS,
+ "OK");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType(MediaType.HTML_UTF_8.toString());
+ PrintWriter out = new PrintWriter(response.getOutputStream());
+ out.print(responseMsg.toString());
+ out.flush();
+
+
+// Logger.info("Received SSO session-data is from IDP: " + entityID
+// + ". Start inderfederation process to restore SSO session ... ");
+// //change to inderfederated session reconstruction
+//
+// Logger.warn("Device Session Transfer with interfederation is not implemented, yet!!!!");
- }
+
} catch (Exception e) {
Logger.error("Parse reveived JSON data-object " + sb.toString() + " FAILED!", e);
- throw new TaskExecutionException(pendingReq, "JSON data is not parseable.", e);
-
+ //throw new TaskExecutionException(pendingReq, "JSON data is not parseable.", e);
+ try {
+ responseMsg.addProperty(
+ SSOTransferConstants.SSOCONTAINER_KEY_STATUS,
+ "FAILED");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = new PrintWriter(response.getOutputStream());
+ out.print(responseMsg.toString());
+ out.flush();
+ } catch (IOException e1) {
+ e1.printStackTrace();
+
+ }
}
} else {
@@ -160,16 +261,26 @@ public class RestoreSSOSessionTask extends AbstractAuthServletTask {
executionContext.put("sessionRestoreFinished", true);
} else {
+ //session is valid --> load MOASession object
+ try {
+ defaultTaskInitialization(request, executionContext);
+
+ } catch (MOAIDException | MOADatabaseException e1) {
+ Logger.error("Database Error! MOASession is not stored!");
+ throw new TaskExecutionException(pendingReq, "Load MOASession FAILED.", e1);
+
+ }
+
DateTime moaSessionCreated = new DateTime(moasession.getSessionCreated().getTime());
- if (moaSessionCreated.plusMinutes(3).isBeforeNow()) {
+ if (moaSessionCreated.plusMinutes(1).isBeforeNow()) {
Logger.warn("No SSO session-container received. Stop authentication process after time-out.");
- throw new TaskExecutionException(pendingReq, "No SSO container received from smartphone app.", null);
+ throw new TaskExecutionException(pendingReq, "No SSO container received from smartphone app.",
+ new MOAIDException("No SSO container received from smartphone app.", null));
} else {
Logger.debug("No restored SSO session found --> Wait a few minutes and check again.");
executionContext.put("sessionRestoreFinished", false);
- VelocityContext context;
try {
//create first step of SSO Transfer GUI
authURL = HTTPUtils.extractAuthURLFromRequest(request);
@@ -180,8 +291,8 @@ public class RestoreSSOSessionTask extends AbstractAuthServletTask {
}
- context = GUIUtils.buildSSOTransferGUI(authURL, pendingReq.getRequestID());
- GUIUtils.printSSOTransferGUI(context, response);
+ GUIUtils.buildSSOTransferGUI(guiBuilder, response,
+ authURL, pendingReq.getRequestID(), nonce, container.getDhParams().getF());
} catch (IOException | MOAIDException e) {
throw new TaskExecutionException(pendingReq, e.getMessage(), e);
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/GUIUtils.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/GUIUtils.java
index ee7a397aa..13a278d1d 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/GUIUtils.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/GUIUtils.java
@@ -22,31 +22,23 @@
*/
package at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils;
-import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
-import java.net.URI;
+import javax.crypto.spec.DHPublicKeySpec;
import javax.servlet.http.HttpServletResponse;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-
import com.google.gson.JsonObject;
-import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
-import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.auth.frontend.builder.DefaultGUIFormBuilderConfiguration;
+import at.gv.egovernment.moa.id.auth.frontend.builder.IGUIFormBuilder;
+import at.gv.egovernment.moa.id.auth.frontend.exception.GUIBuildException;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
-import at.gv.egovernment.moa.id.config.ConfigurationException;
-import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
-import at.gv.egovernment.moa.id.util.VelocityProvider;
+import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants;
+import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.Base64Utils;
+import at.gv.egovernment.moa.util.MiscUtil;
import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;
@@ -54,95 +46,75 @@ import net.glxn.qrgen.image.ImageType;
* @author tlenz
*
*/
-public class GUIUtils {
- private static final String HTMLTEMPLATESDIR = "htmlTemplates/";
- private static final String GUI_HTML_TEMPLATE = "sso_transfer_template.html";
-
+public class GUIUtils {
public static final int REFESH_TIMEOUT = 5 * 1000; //5 sec
- public static VelocityContext buildSSOTransferGUI(String authURL, String pendingReqID) throws ConfigurationException, IOException {
- String containerURL = authURL
- + SSOTransferConstants.SERVLET_SSOTRANSFER_FROM_SMARTPHONE
- + "?" + MOAIDAuthConstants.PARAM_TARGET_PENDINGREQUESTID + "=" + pendingReqID;
-
- JsonObject qrResult = new JsonObject();
- qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_TYPE,
- SSOTransferConstants.SSOCONTAINER_VALUE_TYPE_TRANSER);
- qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_URL, containerURL);
+ public static void buildSSOTransferGUI(
+ IGUIFormBuilder guiBuilder, HttpServletResponse httpResp,
+ String authURL, String pendingReqID) throws ConfigurationException, IOException {
+ buildSSOTransferGUI(guiBuilder, httpResp, authURL, pendingReqID, null, null);
+
+ }
- ByteArrayOutputStream qrStream =
- QRCode.from(qrResult.toString()).to(ImageType.GIF).withSize(300, 300).stream();
- String base64EncodedImage = Base64Utils.encode(qrStream.toByteArray());
- VelocityContext context = new VelocityContext();
- context.put("QRImage", base64EncodedImage);
-
- context.put("successMsg", "Select the SSO Session in your <i>SSO-Transfer App</i> and scan the QR-Code to start the process.");
-
- context.put("timeoutURL", containerURL);
- context.put("timeout", REFESH_TIMEOUT);
-
- return context;
+ /**
+ * @param guiBuilder
+ * @param response
+ * @param authURL
+ * @param requestID
+ * @param nonce
+ * @param dhKeyIDP
+ * @throws ConfigurationException
+ * @throws IOException
+ */
+ public static void buildSSOTransferGUI(IGUIFormBuilder guiBuilder, HttpServletResponse response, String authURL,
+ String requestID, String nonce, DHPublicKeySpec dhKeyIDP) throws ConfigurationException, IOException {
+ try {
+ String containerURL = authURL
+ + SSOTransferConstants.SERVLET_SSOTRANSFER_FROM_SMARTPHONE
+ + "?" + MOAIDAuthConstants.PARAM_TARGET_PENDINGREQUESTID + "=" + requestID;
- }
-
- public static void printSSOTransferGUI(VelocityContext context, HttpServletResponse httpResp) throws MOAIDException {
- try {
- Logger.trace("Initialize VelocityEngine...");
- InputStream is = null;
- String pathLocation = null;
- try {
- String rootconfigdir = AuthConfigurationProviderFactory.getInstance().getRootConfigFileDir();
- pathLocation = rootconfigdir + HTMLTEMPLATESDIR + GUI_HTML_TEMPLATE;
- File file = new File(new URI(pathLocation));
- is = new FileInputStream(file);
- evaluateTemplate(context, httpResp, is);
-
- } catch (Exception e) {
- Logger.warn("SLO Template is not found in configuration directory (" +
- pathLocation + "). Load template from project library ... ");
+
+
+ JsonObject qrResult = new JsonObject();
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_TYPE,
+ SSOTransferConstants.SSOCONTAINER_VALUE_TYPE_TRANSER);
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_URL, containerURL);
+
+ if (MiscUtil.isNotEmpty(nonce))
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_NONCE, nonce);
+
+ if (dhKeyIDP != null) {
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_DH_PUBKEY,
+ Base64Utils.encode(dhKeyIDP.getY().toByteArray()));
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_DH_PRIME,
+ Base64Utils.encode(dhKeyIDP.getP().toByteArray()));
+ qrResult.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_DH_GENERATOR,
+ Base64Utils.encode(dhKeyIDP.getG().toByteArray()));
- try {
- pathLocation = GUI_HTML_TEMPLATE;
- is = Thread.currentThread()
- .getContextClassLoader()
- .getResourceAsStream(pathLocation);
- evaluateTemplate(context, httpResp, is);
+ }
+
+ ByteArrayOutputStream qrStream =
+ QRCode.from(qrResult.toString()).to(ImageType.GIF).withSize(350, 350).stream();
+ String base64EncodedImage = Base64Utils.encode(qrStream.toByteArray());
- } catch (Exception e1) {
- Logger.error("Single LogOut form can not created.", e);
- throw new MOAIDException("Create Single LogOut information FAILED.", null, e);
- }
-
- } finally {
- if (is != null)
- is.close();
+ DefaultGUIFormBuilderConfiguration config = new DefaultGUIFormBuilderConfiguration(
+ authURL,
+ DefaultGUIFormBuilderConfiguration.VIEW_SSO_SESSION_TRANSFER,
+ null);
+
+ config.putCustomParameter("QRImage", base64EncodedImage);
+ config.putCustomParameter("successMsg", "Select the SSO Session in your <i>SSO-Transfer App</i> and scan the QR-Code to start the process.");
+ config.putCustomParameter("timeoutURL", containerURL);
+ config.putCustomParameter("timeout", REFESH_TIMEOUT);
- }
+ guiBuilder.build(response, config, "SSO-Transfer-Module");
- } catch (Exception e) {
- Logger.error("Single LogOut form can not created.", e);
- throw new MOAIDException("Create Single LogOut information FAILED.", null, e);
- }
- }
-
- private static void evaluateTemplate(VelocityContext context, HttpServletResponse httpResp, InputStream is) throws Exception {
-
- VelocityEngine engine = VelocityProvider.getClassPathVelocityEngine();
-
- BufferedReader reader = new BufferedReader(new InputStreamReader(is ));
-
- //set default elements to velocity context
- context.put("contextpath", AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix());
-
- StringWriter writer = new StringWriter();
- //velocityEngine.evaluate(context, writer, "SLO_Template", reader);
- engine.evaluate(context, writer, "SSO Transfer Template", reader);
-
-
- httpResp.setContentType("text/html;charset=UTF-8");
- httpResp.getOutputStream().write(writer.toString().getBytes("UTF-8"));
+ } catch (GUIBuildException e) {
+ Logger.warn("Can not build GUI:'BKU-Selection'. Msg:" + e.getMessage(), e);
+ throw new ConfigurationException("builder.09", new Object[]{e.getMessage()}, e);
+
+ }
- }
-
+ }
}
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/SSOContainerUtils.java b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/SSOContainerUtils.java
index b2ab8b119..0785f767b 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/SSOContainerUtils.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/main/java/at/gv/egovernment/moa/id/auth/modules/ssotransfer/utils/SSOContainerUtils.java
@@ -25,14 +25,31 @@ package at.gv.egovernment.moa.id.auth.modules.ssotransfer.utils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyAgreement;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import javax.crypto.spec.SecretKeySpec;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -81,22 +98,24 @@ import org.w3c.dom.NodeList;
import com.google.gson.JsonObject;
import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
-import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
import at.gv.egovernment.moa.id.auth.exception.ParseException;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.Pair;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.SSOTransferAuthenticationData;
import at.gv.egovernment.moa.id.auth.modules.ssotransfer.data.SSOTransferOnlineApplication;
import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
-import at.gv.egovernment.moa.id.config.ConfigurationException;
-import at.gv.egovernment.moa.id.config.auth.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
+import at.gv.egovernment.moa.id.commons.api.IRequest;
+import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory;
-import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters;
import at.gv.egovernment.moa.id.data.IAuthData;
import at.gv.egovernment.moa.id.data.MISMandate;
-import at.gv.egovernment.moa.id.moduls.IRequest;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder;
import at.gv.egovernment.moa.id.protocols.pvp2x.builder.assertion.PVP2AssertionBuilder;
+import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionAttributeExtractorExeption;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoCredentialsException;
import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SAMLRequestNotSignedException;
@@ -110,6 +129,7 @@ import at.gv.egovernment.moa.id.util.Random;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.Base64Utils;
import at.gv.egovernment.moa.util.MiscUtil;
+import at.gv.util.BpkUtil;
import iaik.x509.X509Certificate;
/**
@@ -148,8 +168,8 @@ public class SSOContainerUtils {
@Autowired SAMLVerificationEngineSP samlVerificationEngine;
@Autowired AuthConfiguration authConfig;
- public void parseSSOContainerToMOASessionDataObject(IRequest pendingReq, AuthenticationSession moasession, Response ssoInformation) throws AssertionAttributeExtractorExeption, ConfigurationException {
- AssertionAttributeExtractor attributeExtractor = new AssertionAttributeExtractor(ssoInformation);
+ public void parseSSOContainerToMOASessionDataObject(IRequest pendingReq, AuthenticationSession moasession, AssertionAttributeExtractor attributeExtractor) throws AssertionAttributeExtractorExeption, ConfigurationException {
+// AssertionAttributeExtractor attributeExtractor = new AssertionAttributeExtractor(ssoInformation);
//TODO: maybe change to correct URL
//set dummy BKU URLx
@@ -250,16 +270,14 @@ public class SSOContainerUtils {
}
- public Response validateReceivedSSOContainer(String signedEncryptedContainer, String entityID) throws IOException, XMLParserException, UnmarshallingException, MOAIDException {
- byte[] base64decodedContainer = Base64Utils.decode(signedEncryptedContainer, false);
-
+ public Response validateReceivedSSOContainer(String signedEncryptedContainer) throws IOException, XMLParserException, UnmarshallingException, MOAIDException {
final BasicParserPool ppMgr = new BasicParserPool();
final HashMap<String, Boolean> features = new HashMap<String, Boolean>();
features.put(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
ppMgr.setBuilderFeatures(features);
ppMgr.setNamespaceAware(true);
- Document document = ppMgr.parse(new ByteArrayInputStream(base64decodedContainer));
+ Document document = ppMgr.parse(new ByteArrayInputStream(signedEncryptedContainer.getBytes()));
Element domElement = document.getDocumentElement();
UnmarshallerFactory saml2UnmarshallerFactory = Configuration.getUnmarshallerFactory();
@@ -297,9 +315,9 @@ public class SSOContainerUtils {
//validate PVP 2.1 assertion
samlVerificationEngine.validateAssertion(ssoContainer, false,
credentials.getIDPAssertionEncryptionCredential(),
- entityID,
- "SSO-Session Transfer module"
- );
+ ssoContainer.getIssuer().getValue(),
+ "SSO-Session Transfer module",
+ false);
return ssoContainer;
} else {
@@ -318,16 +336,15 @@ public class SSOContainerUtils {
public String generateSignedAndEncryptedSSOContainer(String authURL,
- AuthenticationSession authSession, Date date) {
+ AuthenticationSession authSession, Date date, byte[] hashedSecret) {
try {
- String entityID = authURL;
+ String entityID = PVPConfiguration.getInstance().getIDPSSOMetadataService(authURL);
AuthnContextClassRef authnContextClassRef = SAML2Utils
.createSAMLObject(AuthnContextClassRef.class);
authnContextClassRef.setAuthnContextClassRef(authSession.getQAALevel());
NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class);
- String random = Random.nextRandom();
- String nameID = subjectNameID.getValue();
+ String random = Random.nextLongRandom();
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] hash = md.digest((random).getBytes("ISO-8859-1"));
@@ -351,7 +368,7 @@ public class SSOContainerUtils {
IAuthData authData = new SSOTransferAuthenticationData(authConfig, authSession);
Assertion assertion = PVP2AssertionBuilder.buildGenericAssertion(
- authURL,
+ entityID,
entityID,
new DateTime(date.getTime()),
authnContextClassRef,
@@ -361,34 +378,83 @@ public class SSOContainerUtils {
sessionIndex,
subjectConfirmationData.getNotOnOrAfter());
- String ssoDataBlob = buildSSOContainerObject(authURL, assertion, new DateTime(date.getTime()));
+ //build blob with signed session information
+ String ssoDataBlob = buildSSOContainerObject(entityID, assertion, new DateTime(date.getTime()));
+ Logger.debug("Unencrypted SessionBlob:" + ssoDataBlob);
+
+ //encrypt session information with ephemeral key
+ byte[] encPersonData = enOrDeCryptCSR(ssoDataBlob.getBytes(), hashedSecret, Cipher.ENCRYPT_MODE);
+ String encAndEncodedPersonalData = Base64Utils.encode(encPersonData);
+ Logger.debug("Encrypted SessionBlob:" + encAndEncodedPersonalData);
+ //build JSON response
JsonObject container = new JsonObject();
container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_TYPE, SSOTransferConstants.SSOCONTAINER_VALUE_TYPE_SSO);
container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_VALIDTO, subjectConfirmationData.getNotOnOrAfter().toString());
container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_ENTITYID, entityID);
container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_USERID, authData.getGivenName() + " " + authData.getFamilyName());
- container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_SESSION, ssoDataBlob);
+
+ container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_SESSION, encAndEncodedPersonalData);
+ container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_UNIQUEUSERID,
+ BpkUtil.calcBPK(authData.getIdentificationValue(), "AB"));
//TODO
container.addProperty(SSOTransferConstants.SSOCONTAINER_KEY_RESULTENDPOINT, "https://demo.egiz.gv.at");
return container.toString();
- } catch (ConfigurationException | EncryptionException | CredentialsNotAvailableException | SecurityException | ParserConfigurationException | MarshallingException | SignatureException | TransformerFactoryConfigurationError | TransformerException | IOException e) {
+ } catch (ConfigurationException | EncryptionException | CredentialsNotAvailableException | SecurityException | ParserConfigurationException | MarshallingException | SignatureException | TransformerFactoryConfigurationError | TransformerException | IOException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchPaddingException e) {
Logger.warn("SSO container generation FAILED.", e);
}
return null;
}
- private String buildSSOContainerObject(String authURL, Assertion assertion, DateTime date) throws ConfigurationException, EncryptionException, CredentialsNotAvailableException, SecurityException, ParserConfigurationException, MarshallingException, SignatureException, TransformerFactoryConfigurationError, TransformerException, IOException {
+ public byte[] enOrDeCryptCSR(byte[] binBlob, byte[] binSecret, int mode) throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
+ byte[] decrypted = null;
+ SecretKeySpec skeySpec = new SecretKeySpec(binSecret, "AES");
+ Cipher cipher = Cipher.getInstance("AES");
+ cipher.init(mode, skeySpec);
+ decrypted = cipher.doFinal(binBlob);
+
+ return decrypted;
+ }
+
+ public Pair<DHPublicKeySpec, PrivateKey> createSpecificKey(BigInteger p, BigInteger g) throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("DiffieHellman");
+
+ DHParameterSpec param = new DHParameterSpec(p, g);
+ kpg.initialize(param);
+ KeyPair kp = kpg.generateKeyPair();
+
+ KeyFactory kfactory = KeyFactory.getInstance("DiffieHellman");
+
+ Pair<DHPublicKeySpec, PrivateKey> pair = new Pair<DHPublicKeySpec, PrivateKey>(
+ (DHPublicKeySpec) kfactory.getKeySpec(kp.getPublic(), DHPublicKeySpec.class), kp.getPrivate());
+ return pair;
+
+ }
+
+ public byte[] getSecret(DHPublicKeySpec kspectrans, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
+ KeyAgreement aKeyAgree = KeyAgreement.getInstance("DiffieHellman");
+ aKeyAgree.init(privateKey);
+
+ KeyFactory kfactory = KeyFactory.getInstance("DiffieHellman");
+ PublicKey pub = kfactory.generatePublic(kspectrans);
+ aKeyAgree.doPhase(pub, true);
+
+ byte[] secretKey = aKeyAgree.generateSecret();
+ return secretKey;
+
+ }
+
+ private String buildSSOContainerObject(String entityID, Assertion assertion, DateTime date) throws ConfigurationException, EncryptionException, CredentialsNotAvailableException, SecurityException, ParserConfigurationException, MarshallingException, SignatureException, TransformerFactoryConfigurationError, TransformerException, IOException {
Response authResponse = SAML2Utils.createSAMLObject(Response.class);
Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class);
//change to entity value from entity name to IDP EntityID (URL)
- nissuer.setValue(authURL);
+ nissuer.setValue(entityID);
nissuer.setFormat(NameID.ENTITY);
authResponse.setIssuer(nissuer);
@@ -457,7 +523,7 @@ public class SSOContainerUtils {
transformer.transform(source, sr);
sw.close();
- return Base64Utils.encode(sw.toString().getBytes());
+ return sw.toString();
}
@@ -476,7 +542,7 @@ public class SSOContainerUtils {
Logger.info("SSO-Transfer attribute " + el + " is empty!");
} catch (Exception e) {
- Logger.warn("Build SSO-Transfer attribute " + el + " FAILED.", e);
+ Logger.info("Build SSO-Transfer attribute " + el + " FAILED:" + e.getMessage());
}
}
diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java b/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java
index 57f4d11ad..0eb71ec92 100644
--- a/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java
+++ b/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java
@@ -22,6 +22,10 @@
*/
package at.gv.egiz.tests;
+import com.google.gson.JsonObject;
+
+import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants;
+
/**
* @author tlenz
*
@@ -53,6 +57,19 @@ public class Tests {
+ JsonObject responseMsg = new JsonObject();
+ responseMsg.addProperty(
+ SSOTransferConstants.SSOCONTAINER_KEY_STATUS,
+ "OK");
+
+
+ JsonObject levelTwo = new JsonObject();
+ levelTwo.addProperty("test", "12345");
+
+ responseMsg.add("levelTwo", levelTwo );
+
+
+ System.out.println(responseMsg.toString());
// } catch (IOException e) {
// // TODO Auto-generated catch block