Integrate Azure Active Directory Authentication to your website

This blog post is from march 2017. The cloud changes fast so it could be outdated at the moment you read it.

To provide a secure sign in and authorization to your website you will need Azure Active Directory or any other Authentication Provider like Facebook, Twitter or Google. In this blog we will use Azure Active Directory.

We will also use a Web App in Azure and an MVC website build in Visual Studio.

You can download the files and components we will need from here.
Open adalTemplate.js and search for <replace> . Replace <replace> with an actual value.

Logical design

Let’s look at the logical design and how the components integrate and are dependent on each other:

hqdefault

 

At this step I assume that you have Azure Active Directory and have created a Web App in Azure.

  1. We start at building a website in Visual Studio. Create a new MVC website:

image

2. Drag ADAL.js and jquery-3.1.1.min into the project Solution Explorer. You can download them here.

image

3.  Open _Layout.cshtml

4. Drag ADAL.JS and jquery-3.1.1.min into the code of the front page

image

5. Open Index.cshtml

image

6. Under the ADAL.JS section, create a script tag:

image

7.  Paste the content of the adalTemplate.JS file between the Script tags

image

8.  Change the values between all the <> sections. For example <TenantID> and <AppID>

Needs to be between “”

ClientID is the Application ID of the Application in Azure Active Directory Applications

image

9. Change the redirect URL to the URL of your website:

image

 

Now the website is configured to redirect incoming requests to the Azure AD for authorization.

image

GRAPH API

The next step is to use the GRAPH API to get a list of users from Azure AD displayed on our website.

1. In Index.cshtml, the code for the GRAPH API should be pasted in line 131.

image

Code example:

image

2. In Index.cshtml, in div class=”jumbotron” add ID=”Items” to the DIV

image

Active Directory Configuration

1. Log on to Azure, go to Azure Active Directory and create a new application using the values in the next screenshots

image

image

image

The reply URL are the websites where Azure AD is allowed to send the token to.

image

image

Permissions are used to give the token access to certain information in Azure AD. Some information requires admin access but to read the user info and to read the basic profiles of all users, no admin access is needed. Only select those two options.

image

image

The keys section is only used if the application authenticates and not the user, since we want the user to authenticate, the keys section in not necessary.

image

 

Azure Web App configuration

Now that a new application is configured in Azure AD, it is time to set up the Web App.

1. Log on to Azure, Go to the Azure Web App

image

2. Enable App Service Authentication.

image

3. Select Advanced and paste in the Client ID (this is the Application ID of the Application in Azure AD).

image

 

Now when you open the created website, it asks you to log on and afterwards displays a list of users.

 

 

 

Tags:

odata.error
Insufficient privileges to complete the operation
Azure Active Directory
Web App
ADAL
response_type ‘token’ is not supported for the application
oauth2AllowImplicitFlow

Posted in Uncategorized | Tagged , , , , | 2 Comments

TFS Release Management trigger script fails after upgrade from 2013 to 2015 (Update 3)

We are using TFS 2013 Release Management to do deployements. This works great after some modifications (the out-of-box product isn’t that good). One of the modifications is that we use a PowerShell script to trigger releases instead of the option Can trigger release from build

Our 2013 script is:

 <#
        .NOTES
        #------------------------------------------------------------------------------------------------------------
        # Date		    : 08-01-2016
        # Script name  	    : Start-ReleaseManagerBuild.ps1
        # Description  	    : Starts a build from a TFS build.
        #
        # Created by        : Ralph Jansen 
        # Extra module      : 
        # Copyright         : ©2015 all rights reserved.
        # History           : RJA 08-01-2016 Initial version
        #
        #------------------------------------------------------------------------------------------------------------
        
        .DESCRIPTION
        Starts a build from a TFS build.
        
#>

param(
    [string]$releasetemplatename = $Args[0],
    [string]$releasename = $Args[1],  
    [string]$targetstagename = $Args[2])   

cls

$username = "<domain>\<username>"
$password = "<password>"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr


$rmServer = "tfs" 

$builddefinition = [System.Uri]::EscapeDataString($env:TF_BUILD_BUILDDEFINITIONNAME)
$build = [System.Uri]::EscapeDataString($env:TF_BUILD_BUILDNUMBER)

$baseEndpointUrl = "http://$($rmServer):1000/account/releaseManagementService/_apis/releaseManagement" 
$configurationServiceUrl = "$baseEndpointUrl/ConfigurationService" 
$releaseDefinitionServiceUrl = "$baseEndpointUrl/ReleaseDefinitionService" 
$orchestratorServiceUrl = "$baseEndpointUrl/OrchestratorService" 

$escapedUsername = [System.Uri]::EscapeDataString($credentials.UserName) 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetUserByUserName?userName=$escapedUsername&api-version=3.0" 
$userId = $responseXml.Result.User.Id 


$body = "<Filter StatusId='2' IsDeleted='0' UserId='$userId' />" 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$releaseDefinitionServiceUrl/ListReleaseDefinitions?api-version=3.0" -Body $body 
$applicationVersionElt = $responseXml.ApplicationVersionList.ApplicationVersion |  
Where-Object { $_.Name -eq "$releaseTemplateName" } 
$applicationVersionId = $applicationVersionElt.Id 
$releasePathId = $applicationVersionElt.ReleasePathId 


$body = "<Filter ApplicationVersionId='$applicationVersionId' LockRequested='1' LockRequestedById='$userId' />" 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetApplicationVersion?api-version=3.0" -Body $body 
$componentNames = $responseXml.ApplicationVersion.Components.Component.Name 


$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetReleasePath?id=$releasePathId&api-version=3.0" 
$targetStageElt = $responseXml.ReleasePath.Stages.Stage |  
Where-Object { $_.StageTypeName -eq $targetStageName } 
$targetStageId = $targetStageElt.Id 


if ("$releaseName" -eq $null) {$releaseName = "Release: $([DateTime]::Now.ToString('G'))"}
 

$genericProperties = @( 

 """ReleaseName"":""$releaseName""", 

 """ReleaseBuild"":null", 

 """ReleaseBuildChangeset"":null", 

 """TargetStageId"":""$targetStageId""" 

) 

$componentProperties = ($componentNames | ForEach-Object { """$($_):Build"":""$build""" }) 
$json = "{" + ($genericProperties + $componentProperties -join ",`n") + "}" 

$escapedReleaseTemplateName = [System.Uri]::EscapeDataString($releaseTemplateName)
$propertyBag = [System.Uri]::EscapeDataString($json)
$releaseId = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$orchestratorServiceUrl/InitiateRelease?releaseTemplateName=$escapedReleaseTemplateName&deploymentPropertyBag=$propertyBag&api-version=3.0"


$statusId = Invoke-RestMethod -Credential $credentials -Uri "$orchestratorServiceUrl/ReleaseStatus?releaseId=$releaseId"
$statusMapping = @("?", "NotStarted", "InProgress", "Released", "Stopped", "Rejected", "Abandoned" )
$statusMapping[$statusId]

PasteBIN url

Since the upgrade to 2015 U3 this script doesn’t work anymore and gave a “Permission Denied” error in the PowerShell window.

In the Event Log of the TFS server there was an entry:

Event code: 3005 
Event message: An unhandled exception has occurred. 
Event time: 11/23/2016 4:56:06 PM 
Event time (UTC): 11/23/2016 3:56:06 PM 
Event ID: 8de0118d17904ffd9031c36c4373480f 
Event sequence: 13983 
Event occurrence: 42 
Event detail code: 0 
 
Application information: 
    Application domain: /LM/W3SVC/3/ROOT-1-131243652270020196 
    Trust level: Full 
    Application Virtual Path: / 
    Application Path: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Release Management\services\ 
    Machine name: <server> 
 
Process information: 
    Process ID: 5380 
    Process name: w3wp.exe 
    Account name: <account>
 
Exception information: 
    Exception type: IncompatibleVersionException 
    Exception message: Current client version (3) is not compatible with the server version (7.0). You must upgrade the client.
   at Microsoft.TeamFoundation.Release.Services.WebRequestValidators.HttpRequestValidator.IsRequestAuthorized(HttpRequestBase httpRequestBase)
   at Microsoft.TeamFoundation.Release.Services.WebRequestValidators.ServiceModuleAuthorizer.OnAuthorize(HttpContextBase httpContextBase, Action completeRequest)
   at Microsoft.TeamFoundation.Release.Services.ServiceModule.<>c__DisplayClass0_0.<Init>b__1(Object sender, EventArgs e)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

 
 
Request information: 
    Request URL: http://<server>:1000/account/releaseManagementService/_apis/releaseManagement/ReleaseDefinitionService/ListReleaseDefinitions?api-version=3.0 
    Request path: /account/releaseManagementService/_apis/releaseManagement/ReleaseDefinitionService/ListReleaseDefinitions 
    User host address: <ip address>
    User: <username>
    Is authenticated: True 
    Authentication Type: Negotiate 
    Thread account name: <username>
 
Thread information: 
    Thread ID: 8 
    Thread account name: <username>
    Is impersonating: False 
    Stack trace:    at Microsoft.TeamFoundation.Release.Services.WebRequestValidators.HttpRequestValidator.IsRequestAuthorized(HttpRequestBase httpRequestBase)
   at Microsoft.TeamFoundation.Release.Services.WebRequestValidators.ServiceModuleAuthorizer.OnAuthorize(HttpContextBase httpContextBase, Action completeRequest)
   at Microsoft.TeamFoundation.Release.Services.ServiceModule.<>c__DisplayClass0_0.<Init>b__1(Object sender, EventArgs e)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
 
 
Custom event details: 

The Current client version (3) line triggered me to change this in the script to version 7.0. So the trigger script now is:


 <#
        .NOTES
        #------------------------------------------------------------------------------------------------------------
        # Date		    : 23-11-2016
        # Script name  	    : Start-ReleaseManagerBuild.ps1
        # Description  	    : Starts a build from a TFS build for Release Management 2015 (U3)
        #
        # Created by        : Ralph Jansen
        # Extra module      : 
        # Copyright         : ©2015 All rights reserved.
        # History           : RJA 08-01-2016 Initial version
        #
        #------------------------------------------------------------------------------------------------------------
        
        .DESCRIPTION
        Starts a build from a TFS build.
        
#>

param(
    [string]$releasetemplatename = $Args[0],
    [string]$releasename = $Args[1],  
    [string]$targetstagename = $Args[2])   

cls

$username = "<account>"
$password = "<password>"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr


$rmServer = "<servername>" 

$builddefinition = [System.Uri]::EscapeDataString($env:TF_BUILD_BUILDDEFINITIONNAME)
$build = [System.Uri]::EscapeDataString($env:TF_BUILD_BUILDNUMBER)

$baseEndpointUrl = "http://$($rmServer):1000/account/releaseManagementService/_apis/releaseManagement" 
$configurationServiceUrl = "$baseEndpointUrl/ConfigurationService" 
$releaseDefinitionServiceUrl = "$baseEndpointUrl/ReleaseDefinitionService" 
$orchestratorServiceUrl = "$baseEndpointUrl/OrchestratorService" 

$escapedUsername = [System.Uri]::EscapeDataString($credentials.UserName) 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetUserByUserName?userName=$escapedUsername&api-version=3.0" 
$userId = $responseXml.Result.User.Id 


$body = "<Filter StatusId='2' IsDeleted='0' UserId='$userId' />" 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$releaseDefinitionServiceUrl/ListReleaseDefinitions?api-version=7.0" -Body $body 
$applicationVersionElt = $responseXml.ApplicationVersionList.ApplicationVersion |  
Where-Object { $_.Name -eq "$releaseTemplateName" } 
$applicationVersionId = $applicationVersionElt.Id 
$releasePathId = $applicationVersionElt.ReleasePathId 


$body = "<Filter ApplicationVersionId='$applicationVersionId' LockRequested='1' LockRequestedById='$userId' />" 
$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetApplicationVersion?api-version=7.0" -Body $body 
$componentNames = $responseXml.ApplicationVersion.Components.Component.Name 


$responseXml = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$configurationServiceUrl/GetReleasePath?id=$releasePathId&api-version=7.0" 
$targetStageElt = $responseXml.ReleasePath.Stages.Stage |  
Where-Object { $_.StageTypeName -eq $targetStageName } 
$targetStageId = $targetStageElt.Id 


if ("$releaseName" -eq $null) {$releaseName = "Release: $([DateTime]::Now.ToString('G'))"}
 

$genericProperties = @( 

 """ReleaseName"":""$releaseName""", 

 """ReleaseBuild"":null", 

 """ReleaseBuildChangeset"":null", 

 """TargetStageId"":""$targetStageId""" 

) 

$componentProperties = ($componentNames | ForEach-Object { """$($_):Build"":""$build""" }) 
$json = "{" + ($genericProperties + $componentProperties -join ",`n") + "}" 

$escapedReleaseTemplateName = [System.Uri]::EscapeDataString($releaseTemplateName)
$propertyBag = [System.Uri]::EscapeDataString($json)
$releaseId = Invoke-RestMethod -Method Post -Credential $credentials -Uri "$orchestratorServiceUrl/InitiateRelease?releaseTemplateName=$escapedReleaseTemplateName&deploymentPropertyBag=$propertyBag&api-version=3.0"


$statusId = Invoke-RestMethod -Credential $credentials -Uri "$orchestratorServiceUrl/ReleaseStatus?releaseId=$releaseId"
$statusMapping = @("?", "NotStarted", "InProgress", "Released", "Stopped", "Rejected", "Abandoned" )
$statusMapping[$statusId]

PasteBIN URL

Now it works fine, so changing the version is necessary to fix the script.

Posted in Scripts | Tagged , , | Leave a comment

Manage network access to a HDInsight Cluster

Azure HDInsight is an Apache Hadoop distribution powered by the cloud. This means that it handles any amount of data, scaling from terabytes to petabytes on demand. Spin up any number of nodes at any time.

Since HDInsight is a PaaS offering, it is by default publicly accessable from any internet connection. The cluster contains often valuable data of customers. These customers also have requirements how to securely connect to this data, for example using IP restrictions so only their block of IP addresses can connect to the cluster.

In this article we are going to secure the HDInsight cluster so only IP adresses that we specify can connect to it.

  1. Log in to Azure using http://portal.azure.com
  2. You must have a Virtual Network (vNet) to continue, if you don’t have a vNet yet, create one.  This is mandatory.
  3. Click on +New
    1
  4. Search for HDInsight
    image
  5. Select the HDInsight Cluster
    image
  6. Click on Create

    image
  7. Give the HDInsight Cluster a name
    image
  8. Select the correct Cluster Type and Version

    image

  9. Enter the correct credentials
    image
  10. Give the Storage Account and the Container a name
    image
  11. Select the correct sizing of your cluster.
    Be aware that there is a default quota of 60 cores for a Subscription. This can be increased by raising a Support Request.
    See https://azure.microsoft.com/en-us/blog/azure-limits-quotas-increase-requests/ for more information about quotas.
    image
  12. Click on Optional Configuration and select Virtual Network
  13. Select the correct vNet:
    image
  14. Select the correct Subscription
  15. Click on Create and wait 30 minutes:

    image

  16. Now that the HDInsight Cluster is created it is accessible from the public internet. This is something many customers want to prevent, so we need to secure it.
    Since HDInsight is connected to a Private Network, we can assign a Network Security Group (NSG) and then create Inbound Security Rules to allow (not deny) traffic.

    Microsoft requires access from some IP adresses for managebility.  They provide a PowerShell script to create the Network Security Group and give these addresses access to access the cluster. This script can be downloaded here.
    The adjusted script for the environment above, can be seen here.

  17. It is necessary to modify the script and run it. It will create the Network Security Group and have the Microsoft address as inbound rules.
    Note: you cannot set Outbound Security Rules  on the Network Security Group.
    image
  18. Add your own public address, like your datacenter, home IP or office WiFi ip addresses as Inbound Security Rule
    image

 

Now the HDInsight cluster is only available from the addresses and ports that you specified in the Inbound Security Rules.

Posted in Cloud | Tagged , , , , , , , | Leave a comment

TFS / NuGet error–Missing package

Error:

S:\Program Files\Microsoft Team Foundation Server 12.0\Tools\nuget.exe restore “S:\Build\8\<name>\<name>\src\<name>.sln” -NonInteractive

WARNING: Unable to connect to the remote server

WARNING: Unable to connect to the remote server

Unable to find version ‘1.2.2’ of package ‘elmah’.

Unable to find version ‘1.2.2’ of package ‘elmah.corelibrary’

 

Solution:

0. Connect to the internet

1. Open Visual Studio

2. Open the Project

3. Open Tools, NuGet Package Manager, Package Manager Console.

4. Enter: Get-Package -ListAvailable -Filter <name of package>
for example Get-Package -ListAvailable -Filter elmah

 

5. Enter Install-Package <name>
For example: Install-Package elmah

Repeat for each missing package.

6. In Source Control Explorer, right click on the Packages folder of the Project.

7. Click on Add Items to Folder, add the new folders in the local Packages folder.

8. In Source Control Explorer, right click on the Packages folder of the Project.

9. Click on Check in Pending Changes

 

Rebuild the solution.

Posted in Microsoft General | Tagged , , , , , | Leave a comment

Error presenting PowerPoint file in Skype for Business

“<filename>.pptx couldn’t be converted to presentation because Visual Basic for Application (VBA) is not installed on this computer. Please install VBA and try again”

1. Open Add or Remove Programs in Control Panel, select Microsoft Office (Professional Plus) 2013 client and click Change

2. Select Add or Remove Features and click on Continue

image

3. Expand Office Shared Features and check if Visual Basic for Application has been installed.

image

4. Click on Continue

5. Restart Skype for Business and re-try  to present the PowerPoint file.

Posted in Microsoft General | Tagged , | Leave a comment

SQL error “Property Owner is not available for Database

SNAGHTML1e290348

Run the following command to set a new owner, in this example DBO. The database name in this example is newtraders.

use NEWTRADERS

go

sp_changedbowner @loginame = ‘dbo’

go

Posted in Microsoft General | Tagged , , | Leave a comment