You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2015/06/12 13:42:35 UTC

git commit: updated refs/heads/saml-production-grade to f9667b6

Repository: cloudstack
Updated Branches:
  refs/heads/saml-production-grade 45cd42b1a -> f9667b666


CLOUDSTACK-8539: Add metadata refresh timer task and token expiring

- Fix domain path and save it to saml_tokens
- Expire hour old saml tokens
- Refresh metadata based on timer task
- Fix unit tests

Signed-off-by: Rohit Yadav <ro...@shapeblue.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/f9667b66
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/f9667b66
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/f9667b66

Branch: refs/heads/saml-production-grade
Commit: f9667b666a7252f85e3f7331902db1901a66e30d
Parents: 45cd42b
Author: Rohit Yadav <ro...@shapeblue.com>
Authored: Fri Jun 12 14:38:40 2015 +0300
Committer: Rohit Yadav <ro...@shapeblue.com>
Committed: Fri Jun 12 14:42:10 2015 +0300

----------------------------------------------------------------------
 .../command/SAML2LoginAPIAuthenticatorCmd.java  | 26 ++++-----
 .../cloudstack/saml/SAML2AuthManager.java       |  8 +--
 .../cloudstack/saml/SAML2AuthManagerImpl.java   | 57 ++++++++++++++++----
 .../cloudstack/saml/SAMLPluginConstants.java    |  2 +
 .../cloudstack/saml/SAMLTokenDaoImpl.java       | 20 ++++---
 .../GetServiceProviderMetaDataCmdTest.java      | 16 +++++-
 .../org/apache/cloudstack/SAMLUtilsTest.java    |  1 -
 .../SAML2LoginAPIAuthenticatorCmdTest.java      | 25 +++++++--
 8 files changed, 113 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
index 0d935ff..60d4050 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
@@ -18,7 +18,6 @@
 package org.apache.cloudstack.api.command;
 
 import com.cloud.api.response.ApiResponseSerializer;
-import com.cloud.domain.Domain;
 import com.cloud.exception.CloudAuthenticationException;
 import com.cloud.user.Account;
 import com.cloud.user.DomainManager;
@@ -153,6 +152,17 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
                     domainPath = ((String[])params.get(ApiConstants.DOMAIN))[0];
                 }
 
+                if (domainPath != null && !domainPath.isEmpty()) {
+                    if (!domainPath.startsWith("/")) {
+                        domainPath = "/" + domainPath;
+                    }
+                    if (!domainPath.endsWith("/")) {
+                        domainPath = domainPath + "/";
+                    }
+                } else {
+                    domainPath = SAML2AuthManager.SAMLDefaultDomainPath.value();
+                }
+
                 SAMLProviderMetadata spMetadata = _samlAuthManager.getSPMetadata();
                 SAMLProviderMetadata idpMetadata = _samlAuthManager.getIdPMetadata(idpId);
                 if (idpMetadata == null) {
@@ -186,22 +196,8 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
                             params, responseType));
                 }
 
-                String defaultDomainString = SAML2AuthManager.SAMLDefaultDomain.value();
                 String username = null;
                 Long domainId = null;
-                Domain domain = _domainMgr.getDomain(defaultDomainString);
-                if (domain != null) {
-                    domainId = domain.getId();
-                } else {
-                    try {
-                        domainId = Long.parseLong(defaultDomainString);
-                    } catch (NumberFormatException ignore) {
-                    }
-                }
-                if (domainId == null) {
-                    s_logger.error("The default domain ID for SAML users is not set correct, it should be a UUID. ROOT domain will be used.");
-                }
-
                 Issuer issuer = processedSAMLResponse.getIssuer();
                 SAMLProviderMetadata spMetadata = _samlAuthManager.getSPMetadata();
                 SAMLProviderMetadata idpMetadata = _samlAuthManager.getIdPMetadata(issuer.getValue());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java
index 164050f..e4397dd 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java
@@ -55,8 +55,8 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
     public static final ConfigKey<String> SAMLUserAttributeName = new ConfigKey<String>("Advanced", String.class, "saml2.user.attribute", "uid",
             "Attribute name to be looked for in SAML response that will contain the username", true);
 
-    public static final ConfigKey<String> SAMLDefaultDomain = new ConfigKey<String>("Advanced", String.class, "saml2.default.domainid", "1",
-            "The default domain UUID to use if domain information is not found while authenticating users", true);
+    public static final ConfigKey<String> SAMLDefaultDomainPath = new ConfigKey<String>("Advanced", String.class, "saml2.default.domainpath", "/",
+            "The default domain path to use if no domain information is provided on request", true);
 
     public static final ConfigKey<String> SAMLIdentityProviderMetadataURL = new ConfigKey<String>("Advanced", String.class, "saml2.idp.metadata.url", "https://openidp.feide.no/simplesaml/saml2/idp/metadata.php",
             "SAML2 Identity Provider Metadata XML Url", true);
@@ -67,8 +67,8 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
     public static final ConfigKey<String> SAMLSignatureAlgorithm = new ConfigKey<String>("Advanced", String.class, "saml2.sigalg", "SHA1",
             "The algorithm to use to when signing a SAML request. Default is SHA1, allowed algorithms: SHA1, SHA256, SHA384, SHA512", true);
 
-    public static final ConfigKey<Integer> SAMLTimeout = new ConfigKey<Integer>("Advanced", Integer.class, "saml2.timeout", "30000",
-            "SAML2 IDP Metadata Downloading and parsing etc. activity timeout in milliseconds", true);
+    public static final ConfigKey<Integer> SAMLTimeout = new ConfigKey<Integer>("Advanced", Integer.class, "saml2.timeout", "1800",
+            "SAML2 IDP Metadata refresh interval in seconds, minimum value is set to 300", true);
 
     public SAMLProviderMetadata getSPMetadata();
     public SAMLProviderMetadata getIdPMetadata(String entityId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
index b1890e8..146e7a9 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
@@ -33,6 +33,7 @@ import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.security.keystore.KeystoreDao;
 import org.apache.cloudstack.framework.security.keystore.KeystoreVO;
 import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.HttpClient;
 import org.apache.log4j.Logger;
 import org.opensaml.DefaultBootstrap;
 import org.opensaml.common.xml.SAMLConstants;
@@ -80,6 +81,8 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 
 @Component
 @Local(value = {SAML2AuthManager.class, PluggableAPIAuthenticator.class})
@@ -92,7 +95,9 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
     private String idpSingleSignOnUrl;
     private String idpSingleLogOutUrl;
 
-    private HTTPMetadataProvider idpMetaDataProvider;
+    private Timer _timer;
+    private int _refreshInterval = SAMLPluginConstants.SAML_REFRESH_INTERVAL;
+    private HTTPMetadataProvider _idpMetaDataProvider;
 
     @Inject
     private KeystoreDao _ksDao;
@@ -117,6 +122,14 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
         return super.start();
     }
 
+    @Override
+    public boolean stop() {
+        if (_timer != null) {
+            _timer.cancel();
+        }
+        return super.stop();
+    }
+
     private boolean initSP() {
         KeystoreVO keyStoreVO = _ksDao.findByName(SAMLPluginConstants.SAMLSP_KEYPAIR);
         if (keyStoreVO == null) {
@@ -313,22 +326,44 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
         }
     }
 
+    class MetadataRefreshTask extends TimerTask {
+        @Override
+        public void run() {
+            if (_idpMetaDataProvider == null) {
+                return;
+            }
+            s_logger.debug("Starting SAML IDP Metadata Refresh Task");
+            Map <String, SAMLProviderMetadata> metadataMap = new HashMap<String, SAMLProviderMetadata>();
+            try {
+                discoverAndAddIdp(_idpMetaDataProvider.getMetadata(), metadataMap);
+                _idpMetadataMap = metadataMap;
+                expireTokens();
+                s_logger.debug("Finished refreshing SAML Metadata and expiring old auth tokens");
+            } catch (MetadataProviderException e) {
+                s_logger.warn("SAML Metadata Refresh task failed with exception: " + e.getMessage());
+            }
+
+        }
+    }
+
     private boolean setup() {
         if (!initSP()) {
             s_logger.error("SAML Plugin failed to initialize, please fix the configuration and restart management server");
             return false;
         }
-        String idpMetaDataUrl = SAMLIdentityProviderMetadataURL.value();
-        int tolerance = 30000;
-        tolerance = SAMLTimeout.value();
+        _timer = new Timer();
+        final HttpClient client = new HttpClient();
+        final String idpMetaDataUrl = SAMLIdentityProviderMetadataURL.value();
+        if (SAMLTimeout.value() != null && SAMLTimeout.value() > SAMLPluginConstants.SAML_REFRESH_INTERVAL) {
+            _refreshInterval = SAMLTimeout.value();
+        }
         try {
             DefaultBootstrap.bootstrap();
-            idpMetaDataProvider = new HTTPMetadataProvider(idpMetaDataUrl, tolerance);
-            idpMetaDataProvider.setRequireValidMetadata(true);
-            idpMetaDataProvider.setParserPool(new BasicParserPool());
-            idpMetaDataProvider.initialize();
-            _idpMetadataMap.clear();
-            discoverAndAddIdp(idpMetaDataProvider.getMetadata(), _idpMetadataMap);
+            _idpMetaDataProvider = new HTTPMetadataProvider(_timer, client, idpMetaDataUrl);
+            _idpMetaDataProvider.setRequireValidMetadata(true);
+            _idpMetaDataProvider.setParserPool(new BasicParserPool());
+            _idpMetaDataProvider.initialize();
+            _timer.scheduleAtFixedRate(new MetadataRefreshTask(), 0, _refreshInterval * 1000);
         } catch (MetadataProviderException e) {
             s_logger.error("Unable to read SAML2 IDP MetaData URL, error:" + e.getMessage());
             s_logger.error("SAML2 Authentication may be unavailable");
@@ -464,7 +499,7 @@ public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManage
                 SAMLServiceProviderOrgName, SAMLServiceProviderOrgUrl,
                 SAMLServiceProviderSingleSignOnURL, SAMLServiceProviderSingleLogOutURL,
                 SAMLCloudStackRedirectionUrl, SAMLUserAttributeName,
-                SAMLDefaultDomain,
+                SAMLDefaultDomainPath,
                 SAMLIdentityProviderMetadataURL, SAMLDefaultIdentityProviderId,
                 SAMLSignatureAlgorithm, SAMLTimeout};
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLPluginConstants.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLPluginConstants.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLPluginConstants.java
index b61e405..dfd8447 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLPluginConstants.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLPluginConstants.java
@@ -19,6 +19,8 @@
 package org.apache.cloudstack.saml;
 
 public class SAMLPluginConstants {
+    public static final int SAML_REFRESH_INTERVAL = 300;
+
     public static final String SAML_RESPONSE = "SAMLResponse";
     public static final String SAML_IDPID = "SAML_IDPID";
     public static final String SAML_SESSIONID = "SAML_SESSIONID";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLTokenDaoImpl.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLTokenDaoImpl.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLTokenDaoImpl.java
index d6fb938..eb106d9 100644
--- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLTokenDaoImpl.java
+++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAMLTokenDaoImpl.java
@@ -18,10 +18,12 @@ package org.apache.cloudstack.saml;
 
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.exception.CloudRuntimeException;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
 import javax.ejb.Local;
+import java.sql.PreparedStatement;
 
 @DB
 @Component
@@ -32,12 +34,18 @@ public class SAMLTokenDaoImpl extends GenericDaoBase<SAMLTokenVO, Long> implemen
         super();
     }
 
-    @PostConstruct
-    protected void init() {
-    }
-
     @Override
     public void expireTokens() {
-        // TODO: implement delete all from token where timestamp is older than certain thresholds
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+        try {
+            txn.start();
+            String sql = "DELETE FROM `saml_token` WHERE `created` < (NOW() - INTERVAL 1 HOUR)";
+            PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql);
+            pstmt.executeUpdate();
+            txn.commit();
+        } catch (Exception e) {
+            txn.rollback();
+            throw new CloudRuntimeException("Unable to flush old SAML tokens due to exception", e);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/test/org/apache/cloudstack/GetServiceProviderMetaDataCmdTest.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/GetServiceProviderMetaDataCmdTest.java b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/GetServiceProviderMetaDataCmdTest.java
index 32d0fba..5b4d552 100644
--- a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/GetServiceProviderMetaDataCmdTest.java
+++ b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/GetServiceProviderMetaDataCmdTest.java
@@ -24,11 +24,13 @@ import org.apache.cloudstack.api.ApiServerService;
 import org.apache.cloudstack.api.auth.APIAuthenticationType;
 import org.apache.cloudstack.api.command.GetServiceProviderMetaDataCmd;
 import org.apache.cloudstack.saml.SAML2AuthManager;
+import org.apache.cloudstack.saml.SAMLProviderMetadata;
 import org.apache.cloudstack.saml.SAMLUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
 
 import javax.servlet.http.HttpServletRequest;
@@ -36,6 +38,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.lang.reflect.Field;
 import java.security.InvalidKeyException;
+import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.SignatureException;
@@ -75,7 +78,18 @@ public class GetServiceProviderMetaDataCmdTest {
 
         String spId = "someSPID";
         String url = "someUrl";
-        X509Certificate cert = SAMLUtils.generateRandomX509Certificate(SAMLUtils.generateRandomKeyPair());
+        KeyPair kp = SAMLUtils.generateRandomKeyPair();
+        X509Certificate cert = SAMLUtils.generateRandomX509Certificate(kp);
+
+        SAMLProviderMetadata providerMetadata = new SAMLProviderMetadata();
+        providerMetadata.setEntityId("random");
+        providerMetadata.setSigningCertificate(cert);
+        providerMetadata.setEncryptionCertificate(cert);
+        providerMetadata.setKeyPair(kp);
+        providerMetadata.setSsoUrl("http://test.local");
+        providerMetadata.setSloUrl("http://test.local");
+
+        Mockito.when(samlAuthManager.getSPMetadata()).thenReturn(providerMetadata);
 
         String result = cmd.authenticate("command", null, session, "random", HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
         Assert.assertTrue(result.contains("md:EntityDescriptor"));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java
index a55704d..0f68e76 100644
--- a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java
+++ b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/SAMLUtilsTest.java
@@ -56,7 +56,6 @@ public class SAMLUtilsTest extends TestCase {
         LogoutRequest req = SAMLUtils.buildLogoutRequest(logoutUrl, spId);
         assertEquals(req.getDestination(), logoutUrl);
         assertEquals(req.getIssuer().getValue(), spId);
-        assertEquals(req.getSessionIndexes().get(0).getSessionIndex(), sessionIndex);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f9667b66/plugins/user-authenticators/saml2/test/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmdTest.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmdTest.java b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmdTest.java
index c2d4960..00455b9 100644
--- a/plugins/user-authenticators/saml2/test/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmdTest.java
+++ b/plugins/user-authenticators/saml2/test/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmdTest.java
@@ -31,6 +31,7 @@ import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.auth.APIAuthenticationType;
 import org.apache.cloudstack.saml.SAML2AuthManager;
 import org.apache.cloudstack.saml.SAMLPluginConstants;
+import org.apache.cloudstack.saml.SAMLProviderMetadata;
 import org.apache.cloudstack.saml.SAMLUtils;
 import org.joda.time.DateTime;
 import org.junit.Assert;
@@ -43,6 +44,7 @@ import org.opensaml.common.SAMLVersion;
 import org.opensaml.saml2.core.Assertion;
 import org.opensaml.saml2.core.AttributeStatement;
 import org.opensaml.saml2.core.AuthnStatement;
+import org.opensaml.saml2.core.Issuer;
 import org.opensaml.saml2.core.NameID;
 import org.opensaml.saml2.core.NameIDType;
 import org.opensaml.saml2.core.Response;
@@ -52,6 +54,7 @@ import org.opensaml.saml2.core.Subject;
 import org.opensaml.saml2.core.impl.AssertionBuilder;
 import org.opensaml.saml2.core.impl.AttributeStatementBuilder;
 import org.opensaml.saml2.core.impl.AuthnStatementBuilder;
+import org.opensaml.saml2.core.impl.IssuerBuilder;
 import org.opensaml.saml2.core.impl.NameIDBuilder;
 import org.opensaml.saml2.core.impl.ResponseBuilder;
 import org.opensaml.saml2.core.impl.StatusBuilder;
@@ -62,6 +65,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.lang.reflect.Field;
+import java.security.KeyPair;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.Map;
@@ -101,6 +105,9 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
         samlMessage.setIssueInstant(new DateTime(0));
+        Issuer issuer = new IssuerBuilder().buildObject();
+        issuer.setValue("MockedIssuer");
+        samlMessage.setIssuer(issuer);
         Status status = new StatusBuilder().buildObject();
         StatusCode statusCode = new StatusCodeBuilder().buildObject();
         statusCode.setValue(StatusCode.SUCCESS_URI);
@@ -148,7 +155,16 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
 
         String spId = "someSPID";
         String url = "someUrl";
-        X509Certificate cert = SAMLUtils.generateRandomX509Certificate(SAMLUtils.generateRandomKeyPair());
+        KeyPair kp = SAMLUtils.generateRandomKeyPair();
+        X509Certificate cert = SAMLUtils.generateRandomX509Certificate(kp);
+
+        SAMLProviderMetadata providerMetadata = new SAMLProviderMetadata();
+        providerMetadata.setEntityId("random");
+        providerMetadata.setSigningCertificate(cert);
+        providerMetadata.setEncryptionCertificate(cert);
+        providerMetadata.setKeyPair(kp);
+        providerMetadata.setSsoUrl("http://test.local");
+        providerMetadata.setSloUrl("http://test.local");
 
         Mockito.when(session.getAttribute(Mockito.anyString())).thenReturn(null);
 
@@ -158,6 +174,8 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
         user.setId(1000L);
         Mockito.when(userAccountDao.getUserAccount(Mockito.anyString(), Mockito.anyLong())).thenReturn(user);
         Mockito.when(apiServer.verifyUser(Mockito.anyLong())).thenReturn(false);
+        Mockito.when(samlAuthManager.getSPMetadata()).thenReturn(providerMetadata);
+        Mockito.when(samlAuthManager.getIdPMetadata(Mockito.anyString())).thenReturn(providerMetadata);
 
         Map<String, Object[]> params = new HashMap<String, Object[]>();
 
@@ -172,9 +190,8 @@ public class SAML2LoginAPIAuthenticatorCmdTest {
             cmd.authenticate("command", params, session, "random", HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
         } catch (ServerApiException ignored) {
         }
-        //Mockito.verify(domainMgr, Mockito.times(1)).getDomain(Mockito.anyString());
-        //Mockito.verify(userAccountDao, Mockito.times(1)).getUserAccount(Mockito.anyString(), Mockito.anyLong());
-        //Mockito.verify(apiServer, Mockito.times(1)).verifyUser(Mockito.anyLong());
+        Mockito.verify(userAccountDao, Mockito.times(0)).getUserAccount(Mockito.anyString(), Mockito.anyLong());
+        Mockito.verify(apiServer, Mockito.times(0)).verifyUser(Mockito.anyLong());
     }
 
     @Test