Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Commit

Permalink
App role conversion and code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
idwilliams-2 authored Jun 6, 2018
1 parent 67c4575 commit 732bdfa
Show file tree
Hide file tree
Showing 17 changed files with 96 additions and 104 deletions.
44 changes: 40 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,54 @@
# Partner Smart Office Changelog

## 0.6.0 (2018-06-06)

As of this release, we are introducing a code freeze. This means no new configurations or features will be added until after version 1.0 has been released. This code freeze will allow us to focus on addressing issues and simplifying the deployment. If there is a new feature you would like to see added please log a request using the [issue tracker](https://github.com/Microsoft/Partner-Smart-Office/issues), and we will prioritize it accordingly for a future release.

The following enhancements were made with this release

* Added logic to the *ProcessEnvironments* function to write a warning to the console if no environments have been created.
* Modified the authentication configuration for the portal to utilize Azure AD app roles over Azure AD directory roles. This change will make it easier for organizations that are using separate Azure AD tenants for authentication to deploy the solution.

The following issues were addressed with this release

* Deployment may fail with error an stating the key vault name is invalid. Pull request [#24](https://github.com/Microsoft/Partner-Smart-Office/pull/24) introduced the solution for this issue.

This update will require an Azure AD application role be defined and assigned to users that will be managing environments using the portal. Users who are not assigned to this role will receive an access denied error when attempting to access the portal. If you have an existing Azure AD application that you would like to use for the portal then it is recommended that you run the following PowerShell script to create the application role

```powershell
Connect-AzureAD
$adminAppRole = [Microsoft.Open.AzureAD.Model.AppRole]@{
AllowedMemberTypes = @("User");
Description = "Administrative users the have the ability to perform all Smart Office operations.";
DisplayName = "Smart Office Admins";
IsEnabled = $true;
Id = New-Guid;
Value = "SmartOfficeAdmins";
}
# Note the following value can be found in the Azure management portal. Also, it should be a GUID with no trailing spaces.
$appId = Read-Host -Prompt "What is the application identifier for the application you would like to configure?"
$app = Get-AzureADApplication -Filter "AppId eq '$($appId)'"
Set-AzureADApplication -ObjectId $app.ObjectId -AppRoles @($appRoles)
```

If you need information on how to assign users to Azure AD application roles please refer to [How to assign users and groups to an application](https://docs.microsoft.com/en-us/azure/active-directory/application-access-assignment-how-to-add-assignment). Please see the [wiki](https://github.com/Microsoft/Partner-Smart-Office/wiki) for more information on to deploy this solution and create new environments using the portal.

## 0.5.0 (2018-06-05)

The following enhancements were made with this release

* Added a portal to manage the creation and settings for an environment.
* Added the ability to synchronize Azure utilization records for Azure CSP subscriptions. This ability is controlled using the ProcessAzureUsage flag configured on each instance. The default vaule is false for all environments.
* Added the ability to synchronize Azure utilization records for Azure CSP subscriptions. This ability is controlled using the ProcessAzureUsage flag configured on each instance. The default value is false for all environments.

The following bugs were fixed with this release

* A null reference exception was thrown when processing audit records that did not have a customer identifier. This has been fixed through [#19](https://github.com/Microsoft/Partner-Smart-Office/pull/19)
* A format exception was thrown when processing security information for an EA environment. This was fixed through [#20](https://github.com/Microsoft/Partner-Smart-Office/pull/20)

The following changes should be made to existing deployments, so that the portal will function as excepted
The following changes should be made to existing deployments so that the portal will function as excepted

* Add the _Read Directory Data_ application permission to the application you created using the [Create-AzureADApplication.ps1](https://raw.githubusercontent.com/Microsoft/Partner-Smart-Office/master/scripts/Create-AzureADApplication.ps1) script

Expand All @@ -39,7 +75,7 @@ The following changes should be made to existing deployments, so that the portal

The following breaking changes were made with this release.

With this release environments need to be defined in a collection named Environments. This collection can contain the configuration information for CSP and EA environments. The following is an example of what the configuration should look like for a CSP environment.
With this release, environments need to be defined in a collection named Environments. This collection can contain the configuration information for CSP and EA environments. The following is an example of what the configuration should look like for a CSP environment.

```json
{
Expand Down Expand Up @@ -77,7 +113,7 @@ The following is an example of what the configuration should look like for an EA
}
```

In a future release there will be a portal to manage environments and review exceptions.
In a future release, there will be a portal to manage environments and review exceptions.

## 0.0.1 (2018-05-07)

Expand Down
41 changes: 6 additions & 35 deletions azuredeploy.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,11 @@
"description": "Identifier of the Azure AD application configured for the Partner Smart Office solutuion."
}
},
"applicationSecret": {
"authority": {
"type": "string",
"defaultValue": "https://login.microsoftonline.com/common",
"metadata": {
"description": "Secret associated with the Azure AD application configured for the Partner Smart Office solutuion."
}
},
"tenantId": {
"type": "string",
"metadata": {
"description": "Identifier of the tenant where the Azure AD application configured for the Partner Smart Office solutuion exists."
"description": "Address of the Azure AD authority used for portal authentication."
}
},
"repoUrl": {
Expand Down Expand Up @@ -92,7 +87,7 @@
"functionAppName": "[concat(uniquestring(resourceGroup().id), 'functions')]",
"functionIdentityResourceId": "[concat(resourceId('Microsoft.Web/sites', variables('functionAppName')),'/providers/Microsoft.ManagedIdentity/Identities/default')]",
"functionHostingPlanName": "[concat(uniquestring(resourceGroup().id), 'functions')]",
"keyVaultName": "[concat('vault', uniquestring(resourceGroup().id))]",
"keyVaultName": "[concat('vault', uniquestring(resourceGroup().id))]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]",
"storageAccountid": "[concat(resourceGroup().id,'/providers/','Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"webAppIdentityResourceId": "[concat(resourceId('Microsoft.Web/sites', parameters('appName')),'/providers/Microsoft.ManagedIdentity/Identities/default')]",
Expand Down Expand Up @@ -170,21 +165,13 @@
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('webHostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "ActiveDirectoryEndpoint",
"value": "https://login.microsoftonline.com/"
},
{
"name": "ApplicationId",
"value": "[parameters('applicationId')]"
},
{
"name": "ApplicationInsights:InstrumentationKey",
"value": "[reference(concat('Microsoft.Insights/components/', parameters('appName'))).InstrumentationKey]"
},
{
"name": "Authentication:Authority",
"value": "https://login.microsoftonline.com/common"
"value": "[parameters('authority')]"
},
{
"name": "Authentication:ClientId",
Expand All @@ -202,10 +189,6 @@
"name": "PROJECT",
"value": "src\\SmartOffice\\SmartOffice.csproj"
},
{
"name": "TenantId",
"value": "[parameters('tenantId')]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.9.1"
Expand Down Expand Up @@ -366,18 +349,6 @@
"[concat('Microsoft.Web/sites/', variables('functionAppName'))]"
]
},
{
"apiVersion": "2015-06-01",
"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(variables('keyVaultName'), '/', 'ApplicationSecret')]",
"properties": {
"contentType": "text/plain",
"value": "[parameters('applicationSecret')]"
},
"dependsOn": [
"[concat('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]"
]
},
{
"apiVersion": "2015-06-01",
"type": "Microsoft.KeyVault/vaults/secrets",
Expand Down Expand Up @@ -405,4 +376,4 @@
]
}
]
}
}
20 changes: 14 additions & 6 deletions scripts/Create-AzureADApplication.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ try {
"$($Error[0].Exception)"
}

$sessionInfo = Get-AzureADCurrentSessionInfo

$adAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
ResourceAppId = "00000002-0000-0000-c000-000000000000";
ResourceAccess =
Expand All @@ -92,6 +90,15 @@ $adAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
Type = "Scope"}
}

$adminAppRole = [Microsoft.Open.AzureAD.Model.AppRole]@{
AllowedMemberTypes = @("User");
Description = "Administrative users the have the ability to perform all Smart Office operations.";
DisplayName = "Partner Smart Office Admins";
IsEnabled = $true;
Id = New-Guid;
Value = "Admins";
}

$graphAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
ResourceAppId = "00000003-0000-0000-c000-000000000000";
ResourceAccess =
Expand All @@ -106,10 +113,12 @@ $graphAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
Type = "Role"}
}

$SessionInfo = Get-AzureADCurrentSessionInfo
$AppAddress = Read-Host -Prompt "What is the address for the portal (e.g. https://smartoffice.azurewebsites.net)"

Write-Host -ForegroundColor Green "Creating the Azure AD application and related resources..."

$app = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $DisplayName -IdentifierUris "https://$($sessionInfo.TenantDomain)/$((New-Guid).ToString())" -RequiredResourceAccess $adAppAccess, $graphAppAccess
$detail = Get-AzureADTenantDetail
$app = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $DisplayName -IdentifierUris "https://$($SessionInfo.TenantDomain)/$((New-Guid).ToString())" -RequiredResourceAccess $adAppAccess, $graphAppAccess -AppRoles @($adminAppRole) -ReplyUrls @("$($AppAddress)/signin-oidc")
$password = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
$spn = New-AzureADServicePrincipal -AppId $app.AppId -DisplayName $DisplayName

Expand All @@ -119,5 +128,4 @@ if($ConfigurePreconsent) {
}

Write-Host "ApplicationId = $($app.AppId)"
Write-Host "ApplicationSecret = $($password.Value)"
Write-Host "TenantId = $($sessionInfo.TenantId)"
Write-Host "ApplicationSecret = $($password.Value)"
15 changes: 12 additions & 3 deletions scripts/Deploy-PartnerSmartOffice.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,15 @@ $adAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
Type = "Scope"}
}

$adminAppRole = [Microsoft.Open.AzureAD.Model.AppRole]@{
AllowedMemberTypes = @("User");
Description = "Administrative users the have the ability to perform all Smart Office operations.";
DisplayName = "Partner Smart Office Admins";
IsEnabled = $true;
Id = New-Guid;
Value = "Admins";
}

$graphAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
ResourceAppId = "00000003-0000-0000-c000-000000000000";
ResourceAccess =
Expand All @@ -142,8 +151,8 @@ $graphAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{

Write-Host -ForegroundColor Green "Creating the Azure AD application and related resources..."

$app = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $DisplayName -IdentifierUris "https://$($sessionInfo.TenantDomain)/$((New-Guid).ToString())" -RequiredResourceAccess $adAppAccess, $graphAppAccess
$password = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
$app = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $DisplayName -IdentifierUris "https://$($sessionInfo.TenantDomain)/$((New-Guid).ToString())" -RequiredResourceAccess $adAppAccess, $graphAppAccess -AppRoles @($adminAppRole)
New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId
$spn = New-AzureADServicePrincipal -AppId $app.AppId -DisplayName $DisplayName

if($ConfigurePreconsent) {
Expand All @@ -158,4 +167,4 @@ $ResourceGroup = Read-Host -Prompt "Specify a resource group name"
Write-Host -ForegroundColor Green "Deploying Partner Smart Office. Please note this process can take several minutes."

New-AzureRmResourceGroup -Location southcentralus -Name $ResourceGroup
New-AzureRmResourceGroupDeployment -Name $(New-Guid).ToString() -ResourceGroupName $ResourceGroup -TemplateUri https://raw.githubusercontent.com/Microsoft/Partner-Smart-Office/master/azuredeploy.json -appName $appName -applicationId $app.Id -applicationSecret $password -tenantId $sessionInfo.TenantId
New-AzureRmResourceGroupDeployment -Name $(New-Guid).ToString() -ResourceGroupName $ResourceGroup -TemplateUri https://raw.githubusercontent.com/Microsoft/Partner-Smart-Office/master/azuredeploy.json -appName $appName -applicationId $app.Id
2 changes: 1 addition & 1 deletion src/SmartOffice.Data/SmartOffice.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Microsoft.Partner.SmartOffice.Data</AssemblyName>
<RootNamespace>Microsoft.Partner.SmartOffice.Data</RootNamespace>
<Version>0.5.0</Version>
<Version>0.6.0</Version>
<Authors>One Commercial Partner</Authors>
<Company>Microsoft</Company>
<PackageLicenseUrl>https://github.com/Microsoft/Partner-Smart-Office/blob/master/LICENSE</PackageLicenseUrl>
Expand Down
2 changes: 1 addition & 1 deletion src/SmartOffice.Functions/SmartOffice.Functions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
<AssemblyName>Microsoft.Partner.SmartOffice.Functions</AssemblyName>
<RootNamespace>Microsoft.Partner.SmartOffice.Functions</RootNamespace>
<Version>0.5.0</Version>
<Version>0.6.0</Version>
<Company>Microsoft</Company>
<Authors>One Commercial Partner</Authors>
<Product>Partner Smart Office</Product>
Expand Down
2 changes: 1 addition & 1 deletion src/SmartOffice.Models/SmartOffice.Models.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<RootNamespace>Microsoft.Partner.SmartOffice.Models</RootNamespace>
<RepositoryUrl>https://github.com/Microsoft/Partner-Smart-Office.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Version>0.5.0</Version>
<Version>0.6.0</Version>
<Authors>One Commercial Partner</Authors>
<Company>Microsoft</Company>
<PackageLicenseUrl>https://github.com/Microsoft/Partner-Smart-Office/blob/master/LICENSE</PackageLicenseUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class PartnerServiceMessageHandler : DelegatingHandler
/// <summary>
/// Name of the application to be sent with each request.
/// </summary>
private const string ApplicationName = "Partner Smart Office v0.0.4";
private const string ApplicationName = "Partner Smart Office v0.6.0";

/// <summary>
/// Name of the application name header.
Expand Down
12 changes: 6 additions & 6 deletions src/SmartOffice.Services/ServiceClientException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public ServiceClientException(string message, string customerId, HttpStatusCode
/// <summary>
/// Initializes a new instance of the <see cref="ServiceClientException"/> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
/// <param name="info">The serialization infomration that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The context that contains contextual information about the source or destination.</param>
protected ServiceClientException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
{
CustomerId = serializationInfo.GetString("CustomerId");
Expand All @@ -85,15 +85,15 @@ protected ServiceClientException(SerializationInfo serializationInfo, StreamingC
public HttpStatusCode HttpStatusCode { get; private set; }

/// <summary>
/// When overridden in a derived class, sets the <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with information about the exception.
/// When overridden in a derived class, sets the serialization information with information about the exception.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
/// <param name="info">The serialization information that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The context that contains contextual information about the source or destination.</param>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SerializationFormatter" />
/// </PermissionSet>
[SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
Expand Down
2 changes: 1 addition & 1 deletion src/SmartOffice.Services/SmartOffice.Services.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Microsoft.Partner.SmartOffice.Services</AssemblyName>
<RootNamespace>Microsoft.Partner.SmartOffice.Services</RootNamespace>
<Version>0.5.0</Version>
<Version>0.6.0</Version>
<Authors>One Commercial Partner</Authors>
<Company>Microsoft</Company>
<PackageLicenseUrl>https://github.com/Microsoft/Partner-Smart-Office/blob/master/LICENSE</PackageLicenseUrl>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
// -----------------------------------------------------------------------
// <copyright file="PartnerAdminHandler.cs" company="Microsoft">
// <copyright file="SmartOfficeAdminHandler.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace Microsoft.Partner.SmartOffice.Authorization
{
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNetCore.Authorization;

public class PartnerAdminHandler : AuthorizationHandler<PartnerAdminRequirement>
public class SmartOfficeAdminHandler : AuthorizationHandler<SmartOfficeAdminRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PartnerAdminRequirement requirement)
SmartOfficeAdminRequirement requirement)
{

if (context.User.IsInRole("Company Administrator"))
if (context.User.IsInRole("Admins"))
{
if (context.User.HasClaim("IsPartner", "true"))
{
context.Succeed(requirement);
}
context.Succeed(requirement);
}

return Task.CompletedTask;
Expand Down
Loading

0 comments on commit 732bdfa

Please sign in to comment.