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:
parent
ba47053a1c
commit
2ac333e0b7
2
Pipfile
2
Pipfile
@ -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
11
Pipfile.lock
generated
@ -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",
|
||||
|
@ -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(
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user