Add Keystone V3 Support 22/72922/3
authorBenjamin, Max (mb388a) <mb388a@us.att.com>
Fri, 16 Nov 2018 17:23:48 +0000 (12:23 -0500)
committerRob Daugherty <rd472p@att.com>
Wed, 21 Nov 2018 16:06:04 +0000 (16:06 +0000)
update JEL with explicit getVariable call
set project object into scope object
add camunda properties as defaults in application.yaml
added exception handling to keystone v3 case
added in password method to identity object
initial commit of keystone v3 auth support
updated json property values with "_name"
added new columns to cloud identity

Change-Id: Ie08e9893c34d7199197efdb21fe4dd5413b25f44
Issue-ID: SO-1225
Signed-off-by: Benjamin, Max (mb388a) <mb388a@us.att.com>
18 files changed:
adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/AuthenticationMethodFactory.java
adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneAuthHolder.java [new file with mode: 0644]
adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneV3Authentication.java [new file with mode: 0644]
adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/ServiceEndpointNotFoundException.java [new file with mode: 0644]
adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java
adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoKeystoneV3Utils.java [new file with mode: 0644]
adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoNeutronUtils.java
adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoTenantUtilsFactory.java
adapters/mso-adapter-utils/src/test/java/org/onap/so/cloud/authentication/AuthenticationMethodTest.java
adapters/mso-adapter-utils/src/test/resources/__files/KeystoneV3Payload.json [new file with mode: 0644]
adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V4.12.2__AddDomainColumnsCloudIdentity.sql [new file with mode: 0644]
adapters/mso-catalog-db-adapter/src/test/resources/db/migration/afterMigrate.sql
adapters/mso-openstack-adapters/src/test/resources/data.sql
adapters/mso-openstack-adapters/src/test/resources/schema.sql
mso-catalog-db/src/main/java/org/onap/so/db/catalog/beans/CloudIdentity.java
mso-catalog-db/src/main/java/org/onap/so/db/catalog/beans/ServerType.java
mso-catalog-db/src/test/resources/data.sql
mso-catalog-db/src/test/resources/schema.sql

index 1912cd8..49c80b4 100644 (file)
 
 package org.onap.so.cloud.authentication;
 
+import java.util.Collections;
+
+import org.onap.so.cloud.authentication.models.RackspaceAuthentication;
 import org.onap.so.db.catalog.beans.AuthenticationType;
 import org.onap.so.db.catalog.beans.CloudIdentity;
-import org.onap.so.cloud.authentication.models.RackspaceAuthentication;
 import org.onap.so.utils.CryptoUtils;
 import org.springframework.stereotype.Component;
 
 import com.woorea.openstack.keystone.model.Authentication;
 import com.woorea.openstack.keystone.model.authentication.UsernamePassword;
+import com.woorea.openstack.keystone.v3.model.Authentication.Identity;
+import com.woorea.openstack.keystone.v3.model.Authentication.Identity.Password;
+import com.woorea.openstack.keystone.v3.model.Authentication.Identity.Password.User;
+import com.woorea.openstack.keystone.v3.model.Authentication.Identity.Password.User.Domain;
+import com.woorea.openstack.keystone.v3.model.Authentication.Scope;
+import com.woorea.openstack.keystone.v3.model.Authentication.Scope.Project;
 
 /**
  * This factory manages all the wrappers associated to authentication types.
@@ -50,4 +58,30 @@ public final class AuthenticationMethodFactory {
                        return new UsernamePassword (cloudIdentity.getMsoId (), CryptoUtils.decryptCloudConfigPassword(cloudIdentity.getMsoPass ()));
                }
        }
+       
+       
+       public final com.woorea.openstack.keystone.v3.model.Authentication getAuthenticationForV3(CloudIdentity cloudIdentity, String tenantId) {
+               Identity identity = new Identity();
+               Password password = new Password();
+               User user = new User();
+               Domain userDomain = new Domain();
+               Scope scope = new Scope();
+               Project project = new Project();
+               Project.Domain projectDomain = new Project.Domain();
+               userDomain.setName(cloudIdentity.getUserDomainName());
+               projectDomain.setName(cloudIdentity.getProjectDomainName());
+               user.setName(cloudIdentity.getMsoId());
+               user.setPassword(CryptoUtils.decryptCloudConfigPassword(cloudIdentity.getMsoPass()));
+               user.setDomain(userDomain);
+               password.setUser(user);
+               project.setDomain(projectDomain);
+               project.setId(tenantId);
+               scope.setProject(project);
+               identity.setPassword(password);
+               identity.setMethods(Collections.singletonList("password"));
+               com.woorea.openstack.keystone.v3.model.Authentication v3Auth = new com.woorea.openstack.keystone.v3.model.Authentication();
+               v3Auth.setIdentity(identity);
+               v3Auth.setScope(scope);
+               return v3Auth;
+       }
 }
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneAuthHolder.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneAuthHolder.java
new file mode 100644 (file)
index 0000000..1a221a8
--- /dev/null
@@ -0,0 +1,32 @@
+package org.onap.so.cloud.authentication;
+
+import java.io.Serializable;
+import java.util.Calendar;
+
+public class KeystoneAuthHolder implements Serializable {
+
+       private static final long serialVersionUID = -9073252905181739224L;
+       
+       private String id;
+       private Calendar expiration;
+       private String serviceUrl;
+       
+       public String getId() {
+               return id;
+       }
+       public void setId(String id) {
+               this.id = id;
+       }
+       public Calendar getexpiration() {
+               return expiration;
+       }
+       public void setexpiration(Calendar expiration) {
+               this.expiration = expiration;
+       }
+       public String getServiceUrl() {
+               return serviceUrl;
+       }
+       public void setHeatUrl(String serviceUrl) {
+               this.serviceUrl = serviceUrl;
+       }
+}
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneV3Authentication.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/KeystoneV3Authentication.java
new file mode 100644 (file)
index 0000000..05364d0
--- /dev/null
@@ -0,0 +1,113 @@
+package org.onap.so.cloud.authentication;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+import org.onap.so.config.beans.PoConfig;
+import org.onap.so.db.catalog.beans.CloudIdentity;
+import org.onap.so.db.catalog.beans.CloudSite;
+import org.onap.so.openstack.exceptions.MsoException;
+import org.onap.so.openstack.utils.MsoTenantUtils;
+import org.onap.so.openstack.utils.MsoTenantUtilsFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.woorea.openstack.base.client.OpenStackConnectException;
+import com.woorea.openstack.base.client.OpenStackRequest;
+import com.woorea.openstack.base.client.OpenStackResponse;
+import com.woorea.openstack.base.client.OpenStackResponseException;
+import com.woorea.openstack.keystone.v3.Keystone;
+import com.woorea.openstack.keystone.v3.model.Authentication;
+import com.woorea.openstack.keystone.v3.model.Token;
+import com.woorea.openstack.keystone.v3.model.Token.Service;
+
+import net.jodah.failsafe.Failsafe;
+import net.jodah.failsafe.RetryPolicy;
+
+
+@Component
+public class KeystoneV3Authentication {
+
+       @Autowired
+    private AuthenticationMethodFactory authenticationMethodFactory;
+    
+    @Autowired
+    private MsoTenantUtilsFactory tenantUtilsFactory;
+    
+    @Autowired
+       private PoConfig poConfig;
+       
+       public KeystoneAuthHolder getToken(CloudSite cloudSite, String tenantId, String type) throws MsoException {
+               
+               String cloudId = cloudSite.getId();
+        String region = cloudSite.getRegionId();
+
+               CloudIdentity cloudIdentity = cloudSite.getIdentityService();
+               MsoTenantUtils tenantUtils = tenantUtilsFactory.getTenantUtilsByServerType(cloudIdentity.getIdentityServerType());
+        String keystoneUrl = tenantUtils.getKeystoneUrl(cloudId, cloudIdentity);
+        Keystone keystoneTenantClient = new Keystone (keystoneUrl);
+        Authentication v3Credentials = authenticationMethodFactory.getAuthenticationForV3(cloudIdentity, tenantId);
+
+
+       OpenStackRequest<Token> v3Request = keystoneTenantClient.tokens ()
+                .authenticate(v3Credentials);
+       
+       KeystoneAuthHolder holder = makeRequest(v3Request, type, region);
+
+               return holder;
+       }
+       
+       protected KeystoneAuthHolder makeRequest(OpenStackRequest<Token> v3Request, String type, String region) {
+               
+               OpenStackResponse response = Failsafe.with(createRetryPolicy()).get(() -> {
+                       return v3Request.request();
+               });
+               String id = response.header("X-Subject-Token");
+               Token token = response.getEntity(Token.class);
+               KeystoneAuthHolder result = new KeystoneAuthHolder();
+               result.setId(id);
+               result.setexpiration(token.getExpiresAt());
+               result.setHeatUrl(findEndpointURL(token.getCatalog(), type, region, "public"));
+               return result;
+       }
+       
+       protected RetryPolicy createRetryPolicy() {
+               RetryPolicy policy = new RetryPolicy();
+               List<Predicate<Throwable>> result = new ArrayList<>();
+               result.add(e -> {
+                       return e.getCause() instanceof OpenStackResponseException 
+                                       && Arrays.asList(poConfig.getRetryCodes().split(","))
+                                       .contains(Integer.toString(((OpenStackResponseException)e).getStatus()));
+               });
+               result.add(e -> {
+                       return e.getCause() instanceof OpenStackConnectException;
+               });
+               
+               Predicate<Throwable> pred = result.stream().reduce(Predicate::or).orElse(x -> false);
+
+               policy.retryOn(error -> pred.test(error));
+               
+               policy.withDelay(poConfig.getRetryDelay(), TimeUnit.SECONDS)
+               .withMaxRetries(poConfig.getRetryCount());
+               
+               return policy;
+       }
+       
+       protected String findEndpointURL(List<Service> serviceCatalog, String type, String region, String facing) {
+               for(Service service : serviceCatalog) {
+                       if(type.equals(service.getType())) {
+                               for(Service.Endpoint endpoint : service.getEndpoints()) {
+                                       if(region == null || region.equals(endpoint.getRegion())) {
+                                               if(facing.equals(endpoint.getInterface())) {
+                                                       return endpoint.getUrl();
+                                               }
+                                       }
+                               }
+                       }
+               }
+               throw new ServiceEndpointNotFoundException("endpoint url not found");
+       }
+}
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/ServiceEndpointNotFoundException.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloud/authentication/ServiceEndpointNotFoundException.java
new file mode 100644 (file)
index 0000000..3bc57a8
--- /dev/null
@@ -0,0 +1,10 @@
+package org.onap.so.cloud.authentication;
+
+public class ServiceEndpointNotFoundException extends RuntimeException {
+
+       private static final long serialVersionUID = -5347215451284361397L;
+
+       public ServiceEndpointNotFoundException(String message) {
+               super(message);
+       }
+}
index e36d0ff..d87330b 100644 (file)
@@ -24,6 +24,7 @@ package org.onap.so.openstack.utils;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -41,11 +42,15 @@ import org.onap.so.adapters.vdu.VduPlugin;
 import org.onap.so.adapters.vdu.VduStateType;
 import org.onap.so.adapters.vdu.VduStatus;
 import org.onap.so.cloud.CloudConfig;
+import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
+import org.onap.so.cloud.authentication.KeystoneAuthHolder;
+import org.onap.so.cloud.authentication.KeystoneV3Authentication;
+import org.onap.so.cloud.authentication.ServiceEndpointNotFoundException;
 import org.onap.so.db.catalog.beans.CloudIdentity;
 import org.onap.so.db.catalog.beans.CloudSite;
-import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
 import org.onap.so.db.catalog.beans.HeatTemplate;
 import org.onap.so.db.catalog.beans.HeatTemplateParam;
+import org.onap.so.db.catalog.beans.ServerType;
 import org.onap.so.logger.MessageEnum;
 import org.onap.so.logger.MsoAlarmLogger;
 import org.onap.so.logger.MsoLogger;
@@ -115,7 +120,10 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
 
     @Autowired
     private MsoTenantUtilsFactory tenantUtilsFactory;
-
+    
+    @Autowired
+    private KeystoneV3Authentication keystoneV3Authentication;
+    
     private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoHeatUtils.class);
 
     // Properties names and variables (with default values)
@@ -875,7 +883,9 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
      */
     public Heat getHeatClient (CloudSite cloudSite, String tenantId) throws MsoException {
         String cloudId = cloudSite.getId();
-
+        // For DCP/LCP, the region should be the cloudId.
+        String region = cloudSite.getRegionId ();
+        
         // Check first in the cache of previously authorized clients
         String cacheKey = cloudId + ":" + tenantId;
         if (heatClientCache.containsKey (cacheKey)) {
@@ -895,16 +905,58 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
         MsoTenantUtils tenantUtils = tenantUtilsFactory.getTenantUtilsByServerType(cloudIdentity.getIdentityServerType());
         String keystoneUrl = tenantUtils.getKeystoneUrl(cloudId, cloudIdentity);
         LOGGER.debug("keystoneUrl=" + keystoneUrl);
-        Keystone keystoneTenantClient = new Keystone (keystoneUrl);
-        Access access = null;
-        try {
-               Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
-
-               OpenStackRequest <Access> request = keystoneTenantClient.tokens ()
-                       .authenticate (credentials).withTenantId (tenantId);
-
-            access = executeAndRecordOpenstackRequest (request);
-        } catch (OpenStackResponseException e) {
+        String heatUrl = null;
+        String tokenId = null;
+        Calendar expiration = null;
+           try {
+               if (ServerType.KEYSTONE.equals(cloudIdentity.getIdentityServerType())) {
+                       Keystone keystoneTenantClient = new Keystone (keystoneUrl);
+                       Access access = null;
+               
+                       Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
+       
+                       OpenStackRequest <Access> request = keystoneTenantClient.tokens ()
+                              .authenticate (credentials).withTenantId (tenantId);
+       
+                   access = executeAndRecordOpenstackRequest (request);
+               
+                       try {
+                               // Isolate trying to printout the region IDs
+                               try {
+                                       LOGGER.debug("access=" + access.toString());
+                                       for (Access.Service service : access.getServiceCatalog()) {
+                                               List<Access.Service.Endpoint> endpoints = service.getEndpoints();
+                                               for (Access.Service.Endpoint endpoint : endpoints) {
+                                                       LOGGER.debug("AIC returned region=" + endpoint.getRegion());
+                                               }
+                                       }
+                               } catch (Exception e) {
+                                       LOGGER.debug("Encountered an error trying to printout Access object returned from AIC. " + e.getMessage());
+                               }
+                           heatUrl = KeystoneUtils.findEndpointURL (access.getServiceCatalog (), "orchestration", region, "public");
+                           LOGGER.debug("heatUrl=" + heatUrl + ", region=" + region);
+                       } catch (RuntimeException e) {
+                           // This comes back for not found (probably an incorrect region ID)
+                           String error = "AIC did not match an orchestration service for: region=" + region + ",cloud=" + cloudIdentity.getIdentityUrl();
+                           alarmLogger.sendAlarm ("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
+                           throw new MsoAdapterException (error, e);
+                       }
+                       tokenId = access.getToken ().getId ();
+                       expiration = access.getToken ().getExpires ();
+               } else if (ServerType.KEYSTONE_V3.equals(cloudIdentity.getIdentityServerType())) {
+                       try {
+                               KeystoneAuthHolder holder = keystoneV3Authentication.getToken(cloudSite, tenantId, "orchestration");
+                               tokenId = holder.getId();
+                               expiration = holder.getexpiration();
+                               heatUrl = holder.getServiceUrl();
+                       } catch (ServiceEndpointNotFoundException e) {
+                               // This comes back for not found (probably an incorrect region ID)
+                           String error = "cloud did not match an orchestration service for: region=" + region + ",cloud=" + cloudIdentity.getIdentityUrl();
+                           alarmLogger.sendAlarm ("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
+                           throw new MsoAdapterException (error, e);
+                       }
+               }
+           } catch (OpenStackResponseException e) {
             if (e.getStatus () == 401) {
                 // Authentication error.
                 String error = "Authentication Failure: tenant=" + tenantId + ",cloud=" + cloudIdentity.getId ();
@@ -922,39 +974,13 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
             // Catch-all
             throw runtimeExceptionToMsoException (e, TOKEN_AUTH);
         }
-
-        // For DCP/LCP, the region should be the cloudId.
-        String region = cloudSite.getRegionId ();
-        String heatUrl = null;
-        try {
-               // Isolate trying to printout the region IDs
-               try {
-                       LOGGER.debug("access=" + access.toString());
-                       for (Access.Service service : access.getServiceCatalog()) {
-                               List<Access.Service.Endpoint> endpoints = service.getEndpoints();
-                               for (Access.Service.Endpoint endpoint : endpoints) {
-                                       LOGGER.debug("AIC returned region=" + endpoint.getRegion());
-                               }
-                       }
-               } catch (Exception e) {
-                       LOGGER.debug("Encountered an error trying to printout Access object returned from AIC. " + e.getMessage());
-               }
-            heatUrl = KeystoneUtils.findEndpointURL (access.getServiceCatalog (), "orchestration", region, "public");
-            LOGGER.debug("heatUrl=" + heatUrl + ", region=" + region);
-        } catch (RuntimeException e) {
-            // This comes back for not found (probably an incorrect region ID)
-            String error = "AIC did not match an orchestration service for: region=" + region + ",cloud=" + cloudIdentity.getIdentityUrl();
-            alarmLogger.sendAlarm ("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
-            throw new MsoAdapterException (error, e);
-        }
-
         Heat heatClient = new Heat (heatUrl);
-        heatClient.token (access.getToken ().getId ());
+        heatClient.token (tokenId);
 
         heatClientCache.put (cacheKey,
                              new HeatCacheEntry (heatUrl,
-                                                 access.getToken ().getId (),
-                                                 access.getToken ().getExpires ()));
+                                                 tokenId,
+                                                 expiration));
         LOGGER.debug ("Caching HEAT Client for " + cacheKey);
 
         return heatClient;
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoKeystoneV3Utils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoKeystoneV3Utils.java
new file mode 100644 (file)
index 0000000..da1957f
--- /dev/null
@@ -0,0 +1,41 @@
+package org.onap.so.openstack.utils;
+
+import java.util.Map;
+
+import org.onap.so.db.catalog.beans.CloudIdentity;
+import org.onap.so.openstack.beans.MsoTenant;
+import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
+import org.onap.so.openstack.exceptions.MsoException;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MsoKeystoneV3Utils extends MsoTenantUtils {
+
+       @Override
+       public String createTenant(String tenantName, String cloudSiteId, Map<String, String> metadata, boolean backout)
+                       throws MsoException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public MsoTenant queryTenant(String tenantId, String cloudSiteId) throws MsoException, MsoCloudSiteNotFound {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public MsoTenant queryTenantByName(String tenantName, String cloudSiteId)
+                       throws MsoException, MsoCloudSiteNotFound {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public boolean deleteTenant(String tenantId, String cloudSiteId) throws MsoException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public String getKeystoneUrl(String regionId, CloudIdentity cloudIdentity) throws MsoException {
+               return cloudIdentity.getIdentityUrl();
+       }
+
+}
index a9f0a39..b7676e0 100644 (file)
@@ -22,14 +22,19 @@ package org.onap.so.openstack.utils;
 
 
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import org.onap.so.cloud.CloudConfig;
+import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
+import org.onap.so.cloud.authentication.KeystoneAuthHolder;
+import org.onap.so.cloud.authentication.KeystoneV3Authentication;
+import org.onap.so.cloud.authentication.ServiceEndpointNotFoundException;
 import org.onap.so.db.catalog.beans.CloudIdentity;
 import org.onap.so.db.catalog.beans.CloudSite;
-import org.onap.so.cloud.authentication.AuthenticationMethodFactory;
+import org.onap.so.db.catalog.beans.ServerType;
 import org.onap.so.logger.MessageEnum;
 import org.onap.so.logger.MsoAlarmLogger;
 import org.onap.so.logger.MsoLogger;
@@ -78,6 +83,9 @@ public class MsoNeutronUtils extends MsoCommonUtils
        
        @Autowired
        private MsoTenantUtilsFactory tenantUtilsFactory;
+
+       @Autowired
+       private KeystoneV3Authentication keystoneV3Authentication;
        
        private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, MsoNeutronUtils.class);
        
@@ -356,7 +364,8 @@ public class MsoNeutronUtils extends MsoCommonUtils
     private Quantum getNeutronClient(CloudSite cloudSite, String tenantId) throws MsoException
        {
                String cloudId = cloudSite.getId();
-
+               String region = cloudSite.getRegionId();
+               
                // Check first in the cache of previously authorized clients
                String cacheKey = cloudId + ":" + tenantId;
                if (neutronClientCache.containsKey(cacheKey)) {
@@ -378,12 +387,48 @@ public class MsoNeutronUtils extends MsoCommonUtils
                CloudIdentity cloudIdentity = cloudSite.getIdentityService();
                MsoTenantUtils tenantUtils = tenantUtilsFactory.getTenantUtilsByServerType(cloudIdentity.getIdentityServerType());
         final String keystoneUrl = tenantUtils.getKeystoneUrl(cloudId, cloudIdentity);
-               Keystone keystoneTenantClient = new Keystone(keystoneUrl);
-               Access access = null;
+               String neutronUrl = null;
+               String tokenId = null;
+               Calendar expiration = null;
                try {
-                       Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
-                       OpenStackRequest<Access> request = keystoneTenantClient.tokens().authenticate(credentials).withTenantId(tenantId);
-                       access = executeAndRecordOpenstackRequest(request);
+               if (ServerType.KEYSTONE.equals(cloudIdentity.getIdentityServerType())) {
+                               Keystone keystoneTenantClient = new Keystone(keystoneUrl);
+                               Access access = null;
+                               
+                               Authentication credentials = authenticationMethodFactory.getAuthenticationFor(cloudIdentity);
+                               OpenStackRequest<Access> request = keystoneTenantClient.tokens().authenticate(credentials).withTenantId(tenantId);
+                               access = executeAndRecordOpenstackRequest(request);
+                               
+                               
+                               try {
+                                       neutronUrl = KeystoneUtils.findEndpointURL(access.getServiceCatalog(), "network", region, "public");
+                                       if (! neutronUrl.endsWith("/")) {
+                               neutronUrl += "/v2.0/";
+                           }
+                               } catch (RuntimeException e) {
+                                       // This comes back for not found (probably an incorrect region ID)
+                                       String error = "Network service not found: region=" + region + ",cloud=" + cloudIdentity.getId();
+                                       alarmLogger.sendAlarm("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
+                                       throw new MsoAdapterException (error, e);
+                               }
+                               tokenId = access.getToken().getId();
+                               expiration = access.getToken().getExpires();
+               } else if (ServerType.KEYSTONE_V3.equals(cloudIdentity.getIdentityServerType())) {
+                       try {
+                               KeystoneAuthHolder holder = keystoneV3Authentication.getToken(cloudSite, tenantId, "network");
+                               tokenId = holder.getId();
+                               expiration = holder.getexpiration();
+                               neutronUrl = holder.getServiceUrl();
+                               if (! neutronUrl.endsWith("/")) {
+                               neutronUrl += "/v2.0/";
+                           }
+                       } catch (ServiceEndpointNotFoundException e) {
+                               // This comes back for not found (probably an incorrect region ID)
+                                       String error = "Network service not found: region=" + region + ",cloud=" + cloudIdentity.getId();
+                                       alarmLogger.sendAlarm("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
+                                       throw new MsoAdapterException (error, e);
+                       }
+               }
                }
                catch (OpenStackResponseException e) {
                        if (e.getStatus() == 401) {
@@ -408,25 +453,10 @@ public class MsoNeutronUtils extends MsoCommonUtils
                        MsoException me = runtimeExceptionToMsoException(e, "TokenAuth");
                        throw me;
                }
-
-               String region = cloudSite.getRegionId();
-               String neutronUrl = null;
-               try {
-                       neutronUrl = KeystoneUtils.findEndpointURL(access.getServiceCatalog(), "network", region, "public");
-                       if (! neutronUrl.endsWith("/")) {
-                neutronUrl += "/v2.0/";
-            }
-               } catch (RuntimeException e) {
-                       // This comes back for not found (probably an incorrect region ID)
-                       String error = "Network service not found: region=" + region + ",cloud=" + cloudIdentity.getId();
-                       alarmLogger.sendAlarm("MsoConfigurationError", MsoAlarmLogger.CRITICAL, error);
-                       throw new MsoAdapterException (error, e);
-               }
-
                Quantum neutronClient = new Quantum(neutronUrl);
-               neutronClient.token(access.getToken().getId());
+               neutronClient.token(tokenId);
 
-               neutronClientCache.put(cacheKey, new NeutronCacheEntry(neutronUrl, access.getToken().getId(), access.getToken().getExpires()));
+               neutronClientCache.put(cacheKey, new NeutronCacheEntry(neutronUrl, tokenId, expiration));
                LOGGER.debug ("Caching Neutron Client for " + cacheKey);
 
                return neutronClient;
index 79934cc..08c98f3 100644 (file)
@@ -36,6 +36,8 @@ public class MsoTenantUtilsFactory {
        protected CloudConfig cloudConfig;
        @Autowired
        protected MsoKeystoneUtils keystoneUtils;
+       @Autowired
+       protected MsoKeystoneV3Utils keystoneV3Utils;
        
        // based on Cloud IdentityServerType returns ORM or KEYSTONE Utils
        public MsoTenantUtils getTenantUtils(String cloudSiteId) throws MsoCloudSiteNotFound {
@@ -50,6 +52,8 @@ public class MsoTenantUtilsFactory {
                MsoTenantUtils tenantU = null;
                if (ServerType.KEYSTONE.equals(serverType)) {
                        tenantU = keystoneUtils;
+               } else if (ServerType.KEYSTONE_V3.equals(serverType)) {
+                       tenantU = keystoneV3Utils;
                }
                return tenantU;
        }
index 95e4352..a5abe75 100644 (file)
 
 package org.onap.so.cloud.authentication;
 
+import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.onap.so.BaseTest;
+import org.onap.so.cloud.authentication.models.RackspaceAuthentication;
 import org.onap.so.db.catalog.beans.AuthenticationType;
 import org.onap.so.db.catalog.beans.CloudIdentity;
-import org.onap.so.cloud.authentication.models.RackspaceAuthentication;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.onap.so.utils.CryptoUtils;
 
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.woorea.openstack.keystone.model.Authentication;
 import com.woorea.openstack.keystone.model.authentication.UsernamePassword;
 
@@ -42,10 +46,9 @@ import com.woorea.openstack.keystone.model.authentication.UsernamePassword;
  * only are tested.
  *
  */
-public class AuthenticationMethodTest extends BaseTest {
+public class AuthenticationMethodTest {
 
-       @Autowired
-       private AuthenticationMethodFactory authenticationMethodFactory;
+       private AuthenticationMethodFactory authenticationMethodFactory = new AuthenticationMethodFactory();
        /**
         * 
         */
@@ -99,4 +102,20 @@ public class AuthenticationMethodTest extends BaseTest {
                assertTrue(UsernamePassword.class.equals(auth.getClass()));
        
        }
+       
+       @Test
+       public void getAuthenticationForV3Test() throws JsonParseException, JsonMappingException, IOException {
+               
+               CloudIdentity identity = new CloudIdentity();
+               identity.setMsoId("my-username");
+               identity.setMsoPass(CryptoUtils.encryptCloudConfigPassword("my-password"));
+               identity.setProjectDomainName("test-domain");
+               identity.setUserDomainName("user-domain");
+               ObjectMapper mapper = new ObjectMapper();
+               com.woorea.openstack.keystone.v3.model.Authentication expected = 
+                               mapper.readValue(new String(Files.readAllBytes(Paths.get("src/test/resources/__files/KeystoneV3Payload.json"))), com.woorea.openstack.keystone.v3.model.Authentication.class);
+               com.woorea.openstack.keystone.v3.model.Authentication actual = authenticationMethodFactory.getAuthenticationForV3(identity, "project-x");
+               
+               assertThat(actual, sameBeanAs(expected));
+       }
 }
diff --git a/adapters/mso-adapter-utils/src/test/resources/__files/KeystoneV3Payload.json b/adapters/mso-adapter-utils/src/test/resources/__files/KeystoneV3Payload.json
new file mode 100644 (file)
index 0000000..dc6588e
--- /dev/null
@@ -0,0 +1,24 @@
+{
+       "identity": {
+               "methods": [
+                       "password"
+               ],
+               "password": {
+                       "user": {
+                               "domain": {
+                                       "name": "user-domain"
+                               },
+                               "name": "my-username",
+                               "password": "my-password"
+                       }
+               }
+       },
+       "scope": {
+               "project": {
+                       "domain": {
+                               "name": "test-domain"
+                       },
+                       "id": "project-x"
+               }
+       }
+}
diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V4.12.2__AddDomainColumnsCloudIdentity.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V4.12.2__AddDomainColumnsCloudIdentity.sql
new file mode 100644 (file)
index 0000000..e2c4dc8
--- /dev/null
@@ -0,0 +1,3 @@
+ALTER TABLE identity_services
+ADD PROJECT_DOMAIN_NAME VARCHAR(255) DEFAULT NULL,
+ADD USER_DOMAIN_NAME VARCHAR(255) DEFAULT NULL;
index b4916bd..4d5105d 100644 (file)
@@ -4,6 +4,8 @@ CREATE TABLE IF NOT EXISTS `identity_services` (
   `IDENTITY_URL` varchar(200) DEFAULT NULL,
   `MSO_ID` varchar(255) DEFAULT NULL,
   `MSO_PASS` varchar(255) DEFAULT NULL,
+  `PROJECT_DOMAIN_NAME` varchar(255) DEFAULT NULL,
+  `USER_DOMAIN_NAME` varchar(255) DEFAULT NULL,
   `ADMIN_TENANT` varchar(50) DEFAULT NULL,
   `MEMBER_ROLE` varchar(50) DEFAULT NULL,
   `TENANT_METADATA` tinyint(1) DEFAULT 0,
@@ -193,7 +195,7 @@ insert into vnf_components(vnf_id, component_type, heat_template_id, heat_enviro
 
 INSERT INTO `cloudify_managers` (`ID`, `CLOUDIFY_URL`, `USERNAME`, `PASSWORD`, `VERSION`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('mtn13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', NULL, 'MSO_USER', '2018-07-17 14:05:08', '2018-07-17 14:05:08');
 
-INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
+INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `PROJECT_DOMAIN_NAME`, `USER_DOMAIN_NAME`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', NULL, NULL, 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
 
 INSERT INTO `cloud_sites` (`ID`, `REGION_ID`, `IDENTITY_SERVICE_ID`, `CLOUD_VERSION`, `CLLI`, `CLOUDIFY_ID`, `PLATFORM`, `ORCHESTRATOR`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('mtn13', 'mtn13', 'MTN13', '2.5', 'MDT13', 'mtn13', NULL, 'orchestrator', 'MSO_USER', '2018-07-17 14:06:28', '2018-07-17 14:06:28');
 
index 0103564..77df06b 100644 (file)
@@ -152,7 +152,7 @@ INSERT INTO `heat_environment` (`ARTIFACT_UUID`, `NAME`, `VERSION`, `DESCRIPTION
 
 INSERT INTO `cloudify_managers` (`ID`, `CLOUDIFY_URL`, `USERNAME`, `PASSWORD`, `VERSION`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('mtn13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', NULL, 'MSO_USER', '2018-07-17 14:05:08', '2018-07-17 14:05:08');
 
-INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm939454', '93937EA01B94A10A49279D4572B48369', 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
+INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `PROJECT_DOMAIN_NAME`, `USER_DOMAIN_NAME`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm939454', '93937EA01B94A10A49279D4572B48369', null, null, 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
 
 INSERT INTO `cloud_sites` (`ID`, `region_id`, `identity_service_id`, `cloud_version`, `clli`, `cloudify_id`, `platform`, `orchestrator`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'mtn13', 'MTN13', '3.0', 'MDT13', 'mtn13', null, 'orchestrator', '2018-07-17 14:06:28', '2018-07-17 14:06:28');
 
index a051417..0c67123 100644 (file)
@@ -788,6 +788,8 @@ CREATE TABLE IF NOT EXISTS `identity_services` (
   `IDENTITY_URL` varchar(200) DEFAULT NULL,
   `MSO_ID` varchar(255) DEFAULT NULL,
   `MSO_PASS` varchar(255) DEFAULT NULL,
+  `PROJECT_DOMAIN_NAME` varchar(255) DEFAULT NULL,
+  `USER_DOMAIN_NAME` varchar(255) DEFAULT NULL,
   `ADMIN_TENANT` varchar(50) DEFAULT NULL,
   `MEMBER_ROLE` varchar(50) DEFAULT NULL,
   `TENANT_METADATA` tinyint(1) DEFAULT 0,
index b1c81cf..820b47a 100644 (file)
@@ -70,6 +70,16 @@ public class CloudIdentity {
     @Column(name = "MSO_PASS")
     private String msoPass;
     
+    @JsonProperty("project_domain_name")
+    @BusinessKey
+    @Column(name = "PROJECT_DOMAIN_NAME")
+    private String projectDomainName;
+    
+    @JsonProperty("user_domain_name")
+    @BusinessKey
+    @Column(name = "USER_DOMAIN_NAME")
+    private String userDomainName;
+    
     @JsonProperty("admin_tenant")
     @BusinessKey
     @Column(name = "ADMIN_TENANT")
@@ -224,6 +234,21 @@ public class CloudIdentity {
                this.identityAuthenticationType = identityAuthenticationType;
        }
 
+       public String getProjectDomainName() {
+               return projectDomainName;
+       }
+       
+       public void setProjectDomainName(String projectDomainName) {
+               this.projectDomainName = projectDomainName;
+       }
+       
+       public String getUserDomainName() {
+               return userDomainName;
+       }
+       
+       public void setUserDomainName(String userDomainName) {
+               this.userDomainName = userDomainName;
+       }
        @Override
        public CloudIdentity clone() {
                CloudIdentity cloudIdentityCopy = new CloudIdentity();
@@ -237,6 +262,8 @@ public class CloudIdentity {
                cloudIdentityCopy.tenantMetadata = this.tenantMetadata;
                cloudIdentityCopy.identityServerType = this.identityServerType;
                cloudIdentityCopy.identityAuthenticationType = this.identityAuthenticationType;
+               cloudIdentityCopy.projectDomainName = this.projectDomainName;
+               cloudIdentityCopy.userDomainName = this.userDomainName;
 
                return cloudIdentityCopy;
        }
@@ -245,6 +272,7 @@ public class CloudIdentity {
        public String toString() {
                return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("id", getId())
                                .append("identityUrl", getIdentityUrl()).append("msoId", getMsoId())
+                               .append("projectDomain", getProjectDomainName()).append("userDomain", getUserDomainName())
                                .append("adminTenant", getAdminTenant()).append("memberRole", getMemberRole())
                                .append("tenantMetadata", getTenantMetadata()).append("identityServerType", getIdentityServerType())
                                .append("identityAuthenticationType", getIdentityAuthenticationType()).toString();
@@ -262,6 +290,7 @@ public class CloudIdentity {
                return new EqualsBuilder().append(getId(), castOther.getId())
                                .append(getIdentityUrl(), castOther.getIdentityUrl()).append(getMsoId(), castOther.getMsoId())
                                .append(getMsoPass(), castOther.getMsoPass()).append(getAdminTenant(), castOther.getAdminTenant())
+                               .append(getProjectDomainName(), castOther.getProjectDomainName()).append(getUserDomainName(), castOther.getUserDomainName())
                                .append(getMemberRole(), castOther.getMemberRole())
                                .append(getTenantMetadata(), castOther.getTenantMetadata())
                                .append(getIdentityServerType(), castOther.getIdentityServerType())
@@ -271,7 +300,7 @@ public class CloudIdentity {
        @Override
        public int hashCode() {
                return new HashCodeBuilder(1, 31).append(getId()).append(getIdentityUrl()).append(getMsoId())
-                               .append(getMsoPass()).append(getAdminTenant()).append(getMemberRole()).append(getTenantMetadata())
+                               .append(getMsoPass()).append(getProjectDomainName()).append(getUserDomainName()).append(getAdminTenant()).append(getMemberRole()).append(getTenantMetadata())
                                .append(getIdentityServerType()).append(getIdentityAuthenticationType()).toHashCode();
        }
 }
\ No newline at end of file
index eeb5724..14834ea 100644 (file)
@@ -657,7 +657,7 @@ VALUES
 
 INSERT INTO `cloudify_managers` (`ID`, `CLOUDIFY_URL`, `USERNAME`, `PASSWORD`, `VERSION`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('mtn13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', NULL, 'MSO_USER', '2018-07-17 14:05:08', '2018-07-17 14:05:08');
 
-INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
+INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `PROJECT_DOMAIN_NAME`, `USER_DOMAIN_NAME`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('MTN13', 'http://localhost:28090/v2.0', 'm93945', '93937EA01B94A10A49279D4572B48369', NULL, NULL, 'admin', 'admin', 1, 'KEYSTONE', 'USERNAME_PASSWORD', 'MSO_USER', '2018-07-17 14:02:33', '2018-07-17 14:02:33');
 
 INSERT INTO `cloud_sites` (`ID`, `REGION_ID`, `IDENTITY_SERVICE_ID`, `CLOUD_VERSION`, `CLLI`, `CLOUDIFY_ID`, `PLATFORM`, `ORCHESTRATOR`, `LAST_UPDATED_BY`, `CREATION_TIMESTAMP`, `UPDATE_TIMESTAMP`) VALUES ('mtn13', 'mtn13', 'MTN13', '2.5', 'MDT13', 'mtn13', NULL, 'orchestrator', 'MSO_USER', '2018-07-17 14:06:28', '2018-07-17 14:06:28');
 
index 6eaad26..b7d0061 100644 (file)
@@ -837,6 +837,8 @@ CREATE TABLE IF NOT EXISTS `identity_services` (
   `IDENTITY_URL` varchar(200) DEFAULT NULL,
   `MSO_ID` varchar(255) DEFAULT NULL,
   `MSO_PASS` varchar(255) DEFAULT NULL,
+  `PROJECT_DOMAIN_NAME` varchar(255) DEFAULT NULL,
+  `USER_DOMAIN_NAME` varchar(255) DEFAULT NULL,
   `ADMIN_TENANT` varchar(50) DEFAULT NULL,
   `MEMBER_ROLE` varchar(50) DEFAULT NULL,
   `TENANT_METADATA` tinyint(1) DEFAULT 0,