Sample create tenant itegration

This integration works with the happy path, we'll need to expand some fields and handle error states more coherently.
This commit is contained in:
tomdds 2020-01-09 17:29:34 -05:00
parent ba47053a1c
commit 2ac333e0b7
5 changed files with 111 additions and 13 deletions

View File

@ -33,6 +33,8 @@ azure-mgmt-authorization = "*"
azure-mgmt-managementgroups = "*"
azure-mgmt-resource = "*"
transitions = "*"
azure-mgmt-consumption = "*"
adal = "*"
[dev-packages]
bandit = "*"

11
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "63b8f9d203f306a6f0ff20514b024909aa7e64917e1befcc9ea79931b5b4bd34"
"sha256": "a127b88e6c64842786f1868cb93bb1cdc828aa78040ea8ba4079bb3de0316dab"
},
"pipfile-spec": 6,
"requires": {
@ -21,6 +21,7 @@
"sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf",
"sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1"
],
"index": "pypi",
"version": "==1.2.2"
},
"alembic": {
@ -60,6 +61,14 @@
"index": "pypi",
"version": "==0.60.0"
},
"azure-mgmt-consumption": {
"hashes": [
"sha256:035d4b74ca7c47e2683bea17105fd9014c27060336fb6255324ac86b27f70f5b",
"sha256:af319ad6e3ec162a7578563f149e3cdd7d833a62ec80761cfd93caf79467610b"
],
"index": "pypi",
"version": "==3.0.0"
},
"azure-mgmt-managementgroups": {
"hashes": [
"sha256:3d5237947458dc94b4a392141174b1c1258d26611241ee104e9006d1d798f682",

View File

@ -156,12 +156,31 @@ class TenantCSPPayload(BaseCSPPayload):
country_code: str
password_recovery_email_address: str
class Config:
fields = {
"user_id": "userId",
"domain_name": "domainName",
"first_name": "firstName",
"last_name": "lastName",
"country_code": "countryCode",
"password_recovery_email_address": "passwordRecoveryEmailAddress",
}
allow_population_by_field_name = True
class TenantCSPResult(BaseModel):
user_id: str
tenant_id: str
user_object_id: str
class Config:
allow_population_by_field_name = True
fields = {
"user_id": "userId",
"tenant_id": "tenantId",
"user_object_id": "objectId",
}
class BillingProfileAddress(BaseModel):
address: Dict
@ -558,11 +577,15 @@ class AzureSDKProvider(object):
import azure.graphrbac as graphrbac
import azure.common.credentials as credentials
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
import adal
import requests
self.subscription = subscription
self.authorization = authorization
self.adal = adal
self.graphrbac = graphrbac
self.credentials = credentials
self.requests = requests
# may change to a JEDI cloud
self.cloud = AZURE_PUBLIC_CLOUD
@ -657,20 +680,31 @@ class AzureCloudProvider(CloudProviderInterface):
"role_name": role_assignment_id,
}
def create_tenant(self, payload):
# auth as SP that is allowed to create tenant? (tenant creation sp creds)
# create tenant with owner details (populated from portfolio point of contact, pw is generated)
def create_tenant(self, payload: TenantCSPPayload):
sp_token = self._get_sp_token(payload.creds)
if sp_token is None:
raise AuthenticationException("Could not resolve token for tenant creation")
# return tenant id, tenant owner id and tenant owner object id from:
response = {"tenantId": "string", "userId": "string", "objectId": "string"}
return self._ok(
{
"tenant_id": response["tenantId"],
"user_id": response["userId"],
"user_object_id": response["objectId"],
create_tenant_body = payload.dict(by_alias=True)
print(create_tenant_body)
create_tenant_headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {sp_token}",
}
result = self.sdk.requests.post(
"https://management.azure.com/providers/Microsoft.SignUp/createTenant?api-version=2020-01-01-preview",
json=create_tenant_body,
headers=create_tenant_headers,
)
if result.status_code == 200:
return self._ok(TenantCSPResult(**result.json()))
else:
return self._error(result.json())
def create_billing_owner(self, creds, tenant_admin_details):
# authenticate as tenant_admin
# create billing owner identity
@ -838,6 +872,26 @@ class AzureCloudProvider(CloudProviderInterface):
if sub_id_match:
return sub_id_match.group(1)
def _get_sp_token(self, creds):
home_tenant_id = creds.get("home_tenant_id")
client_id = creds.get("client_id")
secret_key = creds.get("secret_key")
# TODO: Make endpoints consts or configs
authentication_endpoint = "https://login.microsoftonline.com/"
resource = "https://management.azure.com/"
context = self.sdk.adal.AuthenticationContext(
authentication_endpoint + home_tenant_id
)
# TODO: handle failure states here
token_response = context.acquire_token_with_client_credentials(
resource, client_id, secret_key
)
return token_response.get("accessToken", None)
def _get_credential_obj(self, creds, resource=None):
return self.sdk.credentials.ServicePrincipalCredentials(

View File

@ -3,7 +3,7 @@ from unittest.mock import Mock
from uuid import uuid4
from atst.domain.csp.cloud import AzureCloudProvider
from atst.domain.csp.cloud import AzureCloudProvider, TenantCSPResult
from tests.mock_azure import mock_azure, AUTH_CREDENTIALS
from tests.factories import EnvironmentFactory, ApplicationFactory
@ -121,3 +121,22 @@ def test_create_policy_definition_succeeds(mock_azure: AzureCloudProvider):
policy_definition_name=properties.get("displayName"),
parameters=mock_policy_definition,
)
def test_create_tenant(mock_azure: AzureCloudProvider):
mock_azure.sdk.adal.AuthenticationContext.return_value.context.acquire_token_with_client_credentials.return_value = {
"accessToken": "TOKEN"
}
mock_result = Mock()
mock_result.json.return_value = {
"objectId": "0a5f4926-e3ee-4f47-a6e3-8b0a30a40e3d",
"tenantId": "60ff9d34-82bf-4f21-b565-308ef0533435",
"userId": "1153801116406515559",
}
mock_result.status_code = 200
mock_azure.sdk.requests.post.return_value = mock_result
result = mock_azure.create_tenant(None, suffix=2)
print(result)
body: TenantCSPResult = result.get("body")
assert body.tenant_id == "60ff9d34-82bf-4f21-b565-308ef0533435"

View File

@ -53,16 +53,30 @@ def mock_policy():
return Mock(spec=policy)
def mock_adal():
import adal
return Mock(spec=adal)
def mock_requests():
import requests
return Mock(spec=requests)
class MockAzureSDK(object):
def __init__(self):
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
self.subscription = mock_subscription()
self.authorization = mock_authorization()
self.adal = mock_adal()
self.managementgroups = mock_managementgroups()
self.graphrbac = mock_graphrbac()
self.credentials = mock_credentials()
self.policy = mock_policy()
self.requests = mock_requests()
# may change to a JEDI cloud
self.cloud = AZURE_PUBLIC_CLOUD