├── .DS_Store ├── 3. ManagedIdentityFunctionCallingAnotherFunction ├── CallingFunction │ ├── host.json │ ├── MyFunctionProj.csproj │ ├── MyFunctionProj.sln │ ├── MyHttpTrigger.cs │ └── .gitignore ├── CalledFunction │ ├── host.json │ ├── local.settings.json │ ├── function.sln │ ├── function.csproj │ ├── Constants.cs │ └── BootLoader.cs ├── armtemplates │ ├── provisionManagedIdentity.json │ ├── calledfunction.json │ └── callingfunction.json └── readme.md ├── 1. Function ├── .vscode │ ├── extensions.json │ ├── settings.json │ ├── launch.json │ └── tasks.json ├── host.json ├── function.sln ├── function.csproj ├── Constants.cs ├── BootLoader.cs └── .gitignore ├── 2. FunctionAttribute ├── .vscode │ ├── extensions.json │ ├── settings.json │ ├── launch.json │ └── tasks.json ├── host.json ├── Services │ ├── IAuthenticationService.cs │ └── AuthenticationService.cs ├── Config │ └── Settings.cs ├── local.settings.json ├── DotNetAuthorizeFunction.sln ├── DotNetAuthorizeFunction.csproj ├── Startup.cs ├── HttpTriggerCSharp.cs ├── AuthorizeAttribute.cs └── .gitignore ├── .gitignore ├── LICENSE └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maliksahil/AzureFunctionsAADDotNet/HEAD/.DS_Store -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CallingFunction/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } -------------------------------------------------------------------------------- /1. Function/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /1. Function/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /2. FunctionAttribute/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "logLevel": { 5 | "DotNetAuthorizeFunction": "Information" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet" 6 | } 7 | } -------------------------------------------------------------------------------- /1. Function/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp2.1/publish", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.projectRuntime": "~2", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "azureFunctions.preDeployTask": "publish" 7 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp2.1/publish", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.projectRuntime": "~2", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "azureFunctions.preDeployTask": "publish" 7 | } -------------------------------------------------------------------------------- /1. Function/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/Services/IAuthenticationService.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace DotNetAuthorizeFunction.Services 6 | { 7 | public interface IAuthenticationService 8 | { 9 | Task ValidateTokenAsync(HttpRequest httpRequest); 10 | } 11 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/Config/Settings.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetAuthorizeFunction.Config 2 | { 3 | public class Settings 4 | { 5 | public string TenantId { get; set; } 6 | 7 | public string ClientId { get; set; } 8 | 9 | public string ClientSecret { get; set; } 10 | 11 | public string Audience { get; set; } 12 | 13 | public string Issuer { get; set; } 14 | 15 | public string MetadataUrl { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # Rider 12 | .idea 13 | 14 | # User-specific files 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # Build results 21 | [Dd]ebug/ 22 | [Dd]ebugPublic/ 23 | [Rr]elease/ 24 | [Rr]eleases/ 25 | x64/ 26 | x86/ 27 | build/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Oo]ut/ 32 | msbuild.log 33 | msbuild.err 34 | msbuild.wrn 35 | 36 | # Visual Studio 2015 37 | .vs/ -------------------------------------------------------------------------------- /2. FunctionAttribute/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet", 6 | "TenantId": "", 7 | "ClientId": "", 8 | "ClientSecret": "", 9 | "Audience": "", 10 | "Issuer": "https://sts.windows.net//", 11 | "MetadataUrl" : "https://login.microsoftonline.com/organizations/v2.0/.well-known/openid-configuration" 12 | } 13 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CallingFunction/MyFunctionProj.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | PreserveNewest 13 | 14 | 15 | PreserveNewest 16 | Never 17 | 18 | 19 | -------------------------------------------------------------------------------- /1. Function/function.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "function", "function.csproj", "{D767DF58-75CA-4529-8D11-440E2208E126}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {D767DF58-75CA-4529-8D11-440E2208E126}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {D767DF58-75CA-4529-8D11-440E2208E126}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {D767DF58-75CA-4529-8D11-440E2208E126}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {D767DF58-75CA-4529-8D11-440E2208E126}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/armtemplates/provisionManagedIdentity.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "identityName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "USER ASSIGNED IDENTITY NAME" 9 | } 10 | } 11 | }, 12 | "resources": [ 13 | { 14 | "type": "Microsoft.ManagedIdentity/userAssignedIdentities", 15 | "name": "[parameters('identityName')]", 16 | "apiVersion": "2018-11-30", 17 | "location": "[resourceGroup().location]" 18 | } 19 | ], 20 | "outputs": { 21 | "identityName": { 22 | "type": "string", 23 | "value": "[parameters('identityName')]" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /1. Function/function.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | Never 18 | 19 | 20 | -------------------------------------------------------------------------------- /2. FunctionAttribute/DotNetAuthorizeFunction.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetAuthorizeFunction", "DotNetAuthorizeFunction.csproj", "{FA7E918B-DB68-4EA4-92C1-819B973FBA52}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {FA7E918B-DB68-4EA4-92C1-819B973FBA52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {FA7E918B-DB68-4EA4-92C1-819B973FBA52}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {FA7E918B-DB68-4EA4-92C1-819B973FBA52}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {FA7E918B-DB68-4EA4-92C1-819B973FBA52}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/function.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "function", "function.csproj", "{D767DF58-75CA-4529-8D11-440E2208E126}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {D767DF58-75CA-4529-8D11-440E2208E126}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {D767DF58-75CA-4529-8D11-440E2208E126}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {D767DF58-75CA-4529-8D11-440E2208E126}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {D767DF58-75CA-4529-8D11-440E2208E126}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CallingFunction/MyFunctionProj.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyFunctionProj", "MyFunctionProj.csproj", "{0F4CF4E1-E9A6-4C80-BE4C-8F7A3D36C068}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {0F4CF4E1-E9A6-4C80-BE4C-8F7A3D36C068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {0F4CF4E1-E9A6-4C80-BE4C-8F7A3D36C068}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {0F4CF4E1-E9A6-4C80-BE4C-8F7A3D36C068}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {0F4CF4E1-E9A6-4C80-BE4C-8F7A3D36C068}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/function.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | Never 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Sahil Malik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /2. FunctionAttribute/DotNetAuthorizeFunction.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | PreserveNewest 17 | 18 | 19 | PreserveNewest 20 | Never 21 | 22 | 23 | -------------------------------------------------------------------------------- /2. FunctionAttribute/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DotNetAuthorizeFunction; 3 | using DotNetAuthorizeFunction.Config; 4 | using DotNetAuthorizeFunction.Services; 5 | using Microsoft.Azure.Functions.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | [assembly: FunctionsStartup(typeof(Startup))] 9 | namespace DotNetAuthorizeFunction 10 | { 11 | public class Startup : FunctionsStartup 12 | { 13 | public override void Configure(IFunctionsHostBuilder builder) 14 | { 15 | builder.Services.Configure(settings => { 16 | settings.TenantId = Environment.GetEnvironmentVariable("TenantId"); 17 | settings.ClientId = Environment.GetEnvironmentVariable("ClientId"); 18 | settings.ClientSecret = Environment.GetEnvironmentVariable("ClientSecret"); 19 | settings.Audience = Environment.GetEnvironmentVariable("Audience"); 20 | settings.Issuer = Environment.GetEnvironmentVariable("Issuer"); 21 | settings.MetadataUrl = Environment.GetEnvironmentVariable("MetadataUrl"); 22 | }); 23 | 24 | builder.Services.AddSingleton(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/HttpTriggerCSharp.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.Extensions.Logging; 8 | using Newtonsoft.Json; 9 | 10 | namespace DotNetAuthorizeFunction 11 | { 12 | public class HttpTriggerCSharp 13 | { 14 | [Authorize] 15 | [FunctionName(nameof(Hello))] 16 | public async Task Hello( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) 18 | { 19 | 20 | log.LogInformation("C# HTTP TRIGGER HANDLER INVOKED"); 21 | 22 | string name = req.Query["name"]; 23 | 24 | string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); 25 | dynamic data = JsonConvert.DeserializeObject(requestBody); 26 | name = name ?? data?.name; 27 | 28 | return name != null 29 | ? (ActionResult)new OkObjectResult($"Hello, {name}. You're authenticated!") 30 | : new BadRequestObjectResult("Please pass a name on the query string or in the request body"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /1. Function/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "problemMatcher": "$msCompile" 9 | }, 10 | { 11 | "label": "build", 12 | "command": "dotnet build", 13 | "type": "shell", 14 | "dependsOn": "clean", 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "clean release", 23 | "command": "dotnet clean --configuration Release", 24 | "type": "shell", 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "publish", 29 | "command": "dotnet publish --configuration Release", 30 | "type": "shell", 31 | "dependsOn": "clean release", 32 | "problemMatcher": "$msCompile" 33 | }, 34 | { 35 | "type": "func", 36 | "dependsOn": "build", 37 | "options": { 38 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.1" 39 | }, 40 | "command": "host start", 41 | "isBackground": true, 42 | "problemMatcher": "$func-watch" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "problemMatcher": "$msCompile" 9 | }, 10 | { 11 | "label": "build", 12 | "command": "dotnet build", 13 | "type": "shell", 14 | "dependsOn": "clean", 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "clean release", 23 | "command": "dotnet clean --configuration Release", 24 | "type": "shell", 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "publish", 29 | "command": "dotnet publish --configuration Release", 30 | "type": "shell", 31 | "dependsOn": "clean release", 32 | "problemMatcher": "$msCompile" 33 | }, 34 | { 35 | "type": "func", 36 | "dependsOn": "build", 37 | "options": { 38 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.1" 39 | }, 40 | "command": "host start", 41 | "isBackground": true, 42 | "problemMatcher": "$func-watch" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /1. Function/Constants.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Collections.Generic; 3 | 4 | namespace Company.Function 5 | { 6 | // demo code, usually want to pull these from key vault or config etc. 7 | internal static class Constants 8 | { 9 | internal static string audience = "https://sahilmalikgmail.onmicrosoft.com/functionapp"; // Get this value from the expose an api, audience uri section example https://appname.tenantname.onmicrosoft.com 10 | internal static string clientID = "d0de483e-2ffc-4847-a51b-39321f038e7f"; // this is the client id, a GUID 11 | internal static string tenant = "sahilmalikgmail.onmicrosoft.com"; // this is your tenant name 12 | internal static string tenantid = "dd1790d8-0aaa-403b-8a1c-43e7cca9b589"; // this is your tenant id (GUID) 13 | 14 | // rest of the values below can be left as is in most circumstances 15 | internal static string aadInstance = "https://login.microsoftonline.com/{0}/v2.0"; 16 | internal static string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant); 17 | internal static List validIssuers = new List() 18 | { 19 | $"https://login.microsoftonline.com/{tenant}/", 20 | $"https://login.microsoftonline.com/{tenant}/v2.0", 21 | $"https://login.windows.net/{tenant}/", 22 | $"https://login.microsoft.com/{tenant}/", 23 | $"https://sts.windows.net/{tenantid}/" 24 | }; 25 | } 26 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/Constants.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Collections.Generic; 3 | 4 | namespace Company.Function 5 | { 6 | // demo code, usually want to pull these from key vault or config etc. 7 | internal static class Constants 8 | { 9 | internal static string audience = "https://sahilcalledfunction.sahilmalikgmail.onmicrosoft.com"; // Get this value from the expose an api, audience uri section example https://appname.tenantname.onmicrosoft.com 10 | internal static string clientID = "d397a3ab-266e-4743-8aac-9f2440d5f159"; // this is the client id, a GUID 11 | internal static string tenant = "sahilmalikgmail.onmicrosoft.com"; // this is your tenant name 12 | internal static string tenantid = "dd1790d8-0aaa-403b-8a1c-43e7cca9b589"; // this is your tenant id (GUID) 13 | 14 | // rest of the values below can be left as is in most circumstances 15 | internal static string aadInstance = "https://login.microsoftonline.com/{0}/v2.0"; 16 | internal static string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant); 17 | internal static List validIssuers = new List() 18 | { 19 | $"https://login.microsoftonline.com/{tenant}/", 20 | $"https://login.microsoftonline.com/{tenant}/v2.0", 21 | $"https://login.windows.net/{tenant}/", 22 | $"https://login.microsoft.com/{tenant}/", 23 | $"https://sts.windows.net/{tenantid}/" 24 | }; 25 | } 26 | } -------------------------------------------------------------------------------- /2. FunctionAttribute/AuthorizeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IdentityModel.Tokens.Jwt; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Security.Claims; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | using DotNetAuthorizeFunction.Services; 10 | using Microsoft.AspNetCore.Http; 11 | using Microsoft.Azure.WebJobs.Host; 12 | 13 | namespace DotNetAuthorizeFunction 14 | { 15 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 16 | public class AuthorizeAttribute : FunctionInvocationFilterAttribute 17 | { 18 | private IAuthenticationService authenticationService; 19 | 20 | public override async Task OnExecutingAsync(FunctionExecutingContext executingContext, CancellationToken cancellationToken) 21 | { 22 | HttpContext context = GetHttpContext(executingContext); 23 | 24 | authenticationService = (IAuthenticationService)context.RequestServices.GetService(typeof(IAuthenticationService)); 25 | 26 | ClaimsPrincipal claimsPrincipal = await authenticationService?.ValidateTokenAsync(context.Request); 27 | bool isAuthenticated = claimsPrincipal != null; 28 | 29 | if (!isAuthenticated) 30 | { 31 | HttpResponse response = context.Response; 32 | 33 | // set unauthorized at response start, overwriting the default 500 error 34 | response.OnStarting(state => 35 | { 36 | response.StatusCode = (int)HttpStatusCode.Unauthorized; 37 | return Task.CompletedTask; 38 | }, null); 39 | 40 | throw new HttpResponseException(HttpStatusCode.Unauthorized); 41 | } 42 | } 43 | 44 | private HttpContext GetHttpContext(FunctionExecutingContext context) 45 | { 46 | var requestArg = context.Arguments.Values.FirstOrDefault(x => x is HttpRequest); 47 | 48 | if (requestArg is HttpRequest request) 49 | return request.HttpContext; 50 | 51 | return null; 52 | } 53 | 54 | } 55 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CallingFunction/MyHttpTrigger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | 11 | using Microsoft.Azure.Services.AppAuthentication; 12 | using System.Net.Http; 13 | using System.Net; 14 | 15 | using System.Data; 16 | using System.Data.SqlClient; 17 | 18 | namespace MyFunctionProj 19 | { 20 | public static class MyHttpTrigger 21 | { 22 | private static readonly HttpClient httpClient = new HttpClient(); 23 | 24 | [FunctionName("MyHttpTrigger")] 25 | public static async Task Run( 26 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, 27 | ILogger log) 28 | { 29 | log.LogInformation("C# HTTP trigger function processed a request."); 30 | try 31 | { 32 | var serviceResourceIDURI = "https://sahilcalledfunction.sahilmalikgmail.onmicrosoft.com"; 33 | var secureFunctionAPIURL = "https://sahilcalledfunction.azurewebsites.net/authenticated"; 34 | var managedIdentityId = "08e84df5-23e7-4c83-8e88-e2b670ec24b8"; 35 | var connectionString = "RunAs=App;AppId=" + managedIdentityId + ";TenantId=dd1790d8-0aaa-403b-8a1c-43e7cca9b589"; 36 | 37 | var azureServiceTokenProvider = new AzureServiceTokenProvider(connectionString); 38 | string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(serviceResourceIDURI); 39 | 40 | // make a post request to the secure service with the access token. 41 | var httpRequestMessage = new HttpRequestMessage 42 | { 43 | Method = HttpMethod.Get, 44 | RequestUri = new Uri(secureFunctionAPIURL), 45 | Headers = { { HttpRequestHeader.Authorization.ToString(), "Bearer " + accessToken } } 46 | }; 47 | log.LogInformation(accessToken); // bad bad bad .. but this is demo code, ensure you don't do this in prod. 48 | var response = await httpClient.SendAsync(httpRequestMessage); 49 | var result = await response.Content.ReadAsStringAsync(); 50 | log.LogInformation(result); 51 | return (ActionResult)new OkObjectResult(result); 52 | } 53 | catch (Exception e) 54 | { 55 | return (ActionResult) 56 | new OkObjectResult(e.ToString()); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/readme.md: -------------------------------------------------------------------------------- 1 | # Register an AAD App 2 | 3 | Register an app with the following characteristics, 4 | 1. Web App 5 | 2. Redirect URI of https://sahilcalledfunction.azurewebsites.net 6 | 3. Under expose an API add an AppID URI of https://sahilcalledfunction.sahilmalikgmail.onmicrosoft.com 7 | 4. Under Authentication enable id token and resource token under implicit grant 8 | 9 | Copy the client id and update Constants.cs under the CalledFunction project 10 | Also update the serviceResourceIDURI under MyHttpTrigger.cs in the CallingFunction Project 11 | 12 | # Create a resource group 13 | 1. Create a resource group, example `az group create -n sahilfunctionapp --location eastus` .. note the name, you'll use this in the various commands below. 14 | 15 | # Deploy the calling function 16 | 1. Create a user-assigned managed identity `az group deployment create --resource-group sahilfunctionapp --template-file armtemplates\provisionManagedIdentity.json --parameters identityName=functionidentity` 17 | 2. Create a function app `az group deployment create --resource-group sahilfunctionapp --template-file armtemplates\callingfunction.json --parameters functionAppName=sahilcallingfunction identityName=functionidentity`, it will ask for the name of the function identity, give it the identity name. 18 | 3. Deploy the calling function, run this command from the calling function directory `func azure functionapp publish sahilcallingfunction` 19 | 20 | # Deploy the called function 21 | 1. Create a function app `az group deployment create --resource-group sahilfunctionapp --template-file armtemplates\calledfunction.json --parameters functionAppName=sahilcalledfunction`, it will ask for the name of the function identity, give it the identity name. 22 | 2. Deploy the called function, run this command from the called function directory `func azure functionapp publish sahilcalledfunction` 23 | 24 | # Overall scripts 25 | 26 | ``` 27 | az login 28 | az group create -n sahilfunctionapp --location eastus 29 | az group deployment create --resource-group sahilfunctionapp --template-file armtemplates/provisionManagedIdentity.json --parameters identityName=functionidentity 30 | az identity show --resource-group sahilfunctionapp --name functionidentity --query "clientId" 31 | ``` 32 | 33 | Here update the MyHttpTrigger.cs class with the clientId of the managed identity. 34 | 35 | ``` 36 | az group deployment create --resource-group sahilfunctionapp --template-file armtemplates/callingfunction.json --parameters functionAppName=sahilcallingfunction identityName=functionidentity 37 | cd CallingFunction 38 | func azure functionapp publish sahilcallingfunction 39 | cd .. 40 | az group deployment create --resource-group sahilfunctionapp --template-file armtemplates/calledfunction.json --parameters functionAppName=sahilcalledfunction 41 | cd CalledFunction 42 | func azure functionapp publish sahilcalledfunction 43 | cd .. 44 | ``` 45 | When done `az group delete -n sahilfunctionapp` -------------------------------------------------------------------------------- /2. FunctionAttribute/Services/AuthenticationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IdentityModel.Tokens.Jwt; 3 | using System.Security.Claims; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using DotNetAuthorizeFunction.Config; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Microsoft.Extensions.Options; 10 | using Microsoft.IdentityModel.Protocols; 11 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 12 | using Microsoft.IdentityModel.Tokens; 13 | 14 | namespace DotNetAuthorizeFunction.Services 15 | { 16 | public class AuthenticationService : IAuthenticationService 17 | { 18 | // set true if you want validation to always pass for debugging 19 | private readonly bool DEBUG = false; 20 | 21 | private readonly IConfigurationManager configManager; 22 | private readonly ILogger log; 23 | private readonly Settings settings; 24 | 25 | // TODO: ADD ILOGGER 26 | public AuthenticationService(IOptions options, ILoggerFactory loggerFactory) 27 | { 28 | settings = options.Value; 29 | log = loggerFactory.CreateLogger(); 30 | 31 | var documentRetriever = new HttpDocumentRetriever 32 | { 33 | RequireHttps = settings.Issuer.StartsWith("https://") 34 | }; 35 | 36 | configManager = new ConfigurationManager( 37 | settings.MetadataUrl, 38 | new OpenIdConnectConfigurationRetriever(), 39 | documentRetriever 40 | ); 41 | } 42 | 43 | public async Task ValidateTokenAsync(HttpRequest req) 44 | { 45 | string token = ExtractToken(req); 46 | if (token == null) 47 | { 48 | log.LogInformation("UNAUTHORIZED. No valid token provided."); 49 | return null; 50 | } 51 | 52 | // for debugging 53 | if (DEBUG && token.Length > 0) return new ClaimsPrincipal(); 54 | 55 | ClaimsPrincipal result = null; 56 | 57 | var config = await configManager.GetConfigurationAsync(CancellationToken.None); 58 | 59 | var validationParam = new TokenValidationParameters() 60 | { 61 | ValidAudiences = new [] { settings.Audience, settings.ClientId }, 62 | ValidIssuer = settings.Issuer, 63 | IssuerSigningKeys = config.SigningKeys 64 | }; 65 | 66 | try 67 | { 68 | var handler = new JwtSecurityTokenHandler(); 69 | result = handler.ValidateToken(token, validationParam, out var validatedToken); 70 | log.LogInformation("Authenticated successfully."); 71 | return result; 72 | } 73 | catch (SecurityTokenException e) 74 | { 75 | log.LogInformation($"UNAUTHORIZED. Reason:\n{e.Message}\n"); 76 | return null; 77 | } 78 | catch (Exception e) 79 | { 80 | log.LogError($"ERROR:\n{e.Message}"); 81 | return null; 82 | } 83 | 84 | } 85 | 86 | private string ExtractToken(HttpRequest req) 87 | { 88 | string authorizationHeader = req?.Headers["Authorization"]; 89 | string[] parts = authorizationHeader?.Split(null) ?? new string[0]; 90 | 91 | // is properly-formatted bearer token 92 | if (parts.Length == 2 && parts[0].Equals("Bearer")) 93 | return parts[1]; 94 | 95 | return null; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /1. Function/BootLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | 11 | using System.Collections.Generic; 12 | using System.Globalization; 13 | using System.IdentityModel.Tokens.Jwt; 14 | using Microsoft.IdentityModel.Tokens; 15 | using Microsoft.IdentityModel.Protocols; 16 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 17 | using System.Linq; 18 | using System.Security.Claims; 19 | 20 | namespace Company.Function 21 | { 22 | public static class BootLoader 23 | { 24 | [FunctionName("BootLoader")] 25 | public static async Task Run( 26 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", 27 | Route = "{requestedRoute}")] HttpRequest req, 28 | string requestedRoute, 29 | ILogger log) 30 | { 31 | log.LogInformation("C# HTTP trigger function processed a request."); 32 | requestedRoute = requestedRoute.ToLower(); 33 | switch (requestedRoute) 34 | { 35 | case "anonymous": 36 | return Anonymous(req, log); 37 | case "authenticated": 38 | return await Authenticated(req, log); 39 | default: 40 | break; 41 | } 42 | return (ActionResult)new OkObjectResult(requestedRoute); 43 | } 44 | 45 | private static IActionResult Anonymous(HttpRequest req, ILogger log) 46 | { 47 | return (ActionResult)new OkObjectResult("anonymous"); 48 | } 49 | 50 | private static async Task Authenticated(HttpRequest req, ILogger log) 51 | { 52 | var accessToken = GetAccessToken(req); 53 | var claimsPrincipal = await ValidateAccessToken(accessToken, log); 54 | if (claimsPrincipal != null) 55 | { 56 | return (ActionResult)new OkObjectResult(claimsPrincipal.Identity.Name); 57 | } 58 | else 59 | { 60 | return (ActionResult)new UnauthorizedResult(); 61 | } 62 | } 63 | 64 | private static string GetAccessToken(HttpRequest req) 65 | { 66 | var authorizationHeader = req.Headers?["Authorization"]; 67 | string[] parts = authorizationHeader?.ToString().Split(null) ?? new string[0]; 68 | if (parts.Length == 2 && parts[0].Equals("Bearer")) 69 | return parts[1]; 70 | return null; 71 | } 72 | 73 | private static async Task ValidateAccessToken(string accessToken, ILogger log) 74 | { 75 | var audience = Constants.audience; 76 | var clientID = Constants.clientID; 77 | var tenant = Constants.tenant; 78 | var tenantid = Constants.tenantid; 79 | var aadInstance = Constants.aadInstance; 80 | var authority = Constants.authority; 81 | var validIssuers = Constants.validIssuers; 82 | 83 | // Debugging purposes only, set this to false for production 84 | Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; 85 | 86 | ConfigurationManager configManager = 87 | new ConfigurationManager( 88 | $"{authority}/.well-known/openid-configuration", 89 | new OpenIdConnectConfigurationRetriever()); 90 | 91 | OpenIdConnectConfiguration config = null; 92 | config = await configManager.GetConfigurationAsync(); 93 | 94 | ISecurityTokenValidator tokenValidator = new JwtSecurityTokenHandler(); 95 | 96 | // Initialize the token validation parameters 97 | TokenValidationParameters validationParameters = new TokenValidationParameters 98 | { 99 | // App Id URI and AppId of this service application are both valid audiences. 100 | ValidAudiences = new[] { audience, clientID }, 101 | 102 | // Support Azure AD V1 and V2 endpoints. 103 | ValidIssuers = validIssuers, 104 | IssuerSigningKeys = config.SigningKeys 105 | }; 106 | 107 | try 108 | { 109 | SecurityToken securityToken; 110 | var claimsPrincipal = tokenValidator.ValidateToken(accessToken, validationParameters, out securityToken); 111 | return claimsPrincipal; 112 | } 113 | catch (Exception ex) 114 | { 115 | log.LogError(ex.ToString()); 116 | } 117 | return null; 118 | } 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CalledFunction/BootLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | 11 | using System.Collections.Generic; 12 | using System.Globalization; 13 | using System.IdentityModel.Tokens.Jwt; 14 | using Microsoft.IdentityModel.Tokens; 15 | using Microsoft.IdentityModel.Protocols; 16 | using Microsoft.IdentityModel.Protocols.OpenIdConnect; 17 | using System.Linq; 18 | using System.Security.Claims; 19 | 20 | namespace Company.Function 21 | { 22 | public static class BootLoader 23 | { 24 | [FunctionName("BootLoader")] 25 | public static async Task Run( 26 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", 27 | Route = "{requestedRoute}")] HttpRequest req, 28 | string requestedRoute, 29 | ILogger log) 30 | { 31 | log.LogInformation("C# HTTP trigger function processed a request."); 32 | requestedRoute = requestedRoute.ToLower(); 33 | switch (requestedRoute) 34 | { 35 | case "anonymous": 36 | return Anonymous(req, log); 37 | case "authenticated": 38 | return await Authenticated(req, log); 39 | default: 40 | break; 41 | } 42 | return (ActionResult)new OkObjectResult(requestedRoute); 43 | } 44 | 45 | private static IActionResult Anonymous(HttpRequest req, ILogger log) 46 | { 47 | return (ActionResult)new OkObjectResult("anonymous"); 48 | } 49 | 50 | private static async Task Authenticated(HttpRequest req, ILogger log) 51 | { 52 | var accessToken = GetAccessToken(req); 53 | log.LogInformation(accessToken); // bad bad bad .. but this is demo code, ensure you don't do this in prod. 54 | var claimsPrincipal = await ValidateAccessToken(accessToken, log); 55 | if (claimsPrincipal != null) 56 | { 57 | return (ActionResult)new OkObjectResult(claimsPrincipal.FindFirst("appid").Value); 58 | } 59 | else 60 | { 61 | return (ActionResult)new UnauthorizedResult(); 62 | } 63 | } 64 | 65 | private static string GetAccessToken(HttpRequest req) 66 | { 67 | var authorizationHeader = req.Headers?["Authorization"]; 68 | string[] parts = authorizationHeader?.ToString().Split(null) ?? new string[0]; 69 | if (parts.Length == 2 && parts[0].Equals("Bearer")) 70 | return parts[1]; 71 | return null; 72 | } 73 | 74 | private static async Task ValidateAccessToken(string accessToken, ILogger log) 75 | { 76 | var audience = Constants.audience; 77 | var clientID = Constants.clientID; 78 | var tenant = Constants.tenant; 79 | var tenantid = Constants.tenantid; 80 | var aadInstance = Constants.aadInstance; 81 | var authority = Constants.authority; 82 | var validIssuers = Constants.validIssuers; 83 | 84 | // Debugging purposes only, set this to false for production 85 | Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; 86 | 87 | ConfigurationManager configManager = 88 | new ConfigurationManager( 89 | $"{authority}/.well-known/openid-configuration", 90 | new OpenIdConnectConfigurationRetriever()); 91 | 92 | OpenIdConnectConfiguration config = null; 93 | config = await configManager.GetConfigurationAsync(); 94 | 95 | ISecurityTokenValidator tokenValidator = new JwtSecurityTokenHandler(); 96 | 97 | // Initialize the token validation parameters 98 | TokenValidationParameters validationParameters = new TokenValidationParameters 99 | { 100 | // App Id URI and AppId of this service application are both valid audiences. 101 | ValidAudiences = new[] { audience, clientID }, 102 | 103 | // Support Azure AD V1 and V2 endpoints. 104 | ValidIssuers = validIssuers, 105 | IssuerSigningKeys = config.SigningKeys 106 | }; 107 | 108 | try 109 | { 110 | SecurityToken securityToken; 111 | var claimsPrincipal = tokenValidator.ValidateToken(accessToken, validationParameters, out securityToken); 112 | return claimsPrincipal; 113 | } 114 | catch (Exception ex) 115 | { 116 | log.LogError(ex.ToString()); 117 | } 118 | return null; 119 | } 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This repo contains the various identity related scenarios with Azure functions in DotNet 2 | 3 | ## You can find 4 | 1. DotNet and Azure Functions examples at https://github.com/maliksahil/AzureFunctionsAADDotNet 5 | 2. NodeJS and Azure Functions examples at https://github.com/maliksahil/AzureFunctionsAADNodeJS 6 | 3. Python and Azure Functions examples at https://github.com/maliksahil/AzureFunctionsAADPython 7 | 8 | You will find two examples in this repo 9 | 1. Function - which shows how to do bearer token validation using MSAL 10 | 2. FunctionAttribute - same but gives you an AuthorizeAttribute, currently depends on some obsolete APIs. 11 | 12 | ## Prerequisites 13 | 1. You must have Visual Studio Code installed 14 | 2. You must have Azure Functions core tools installed `npm install -g azure-functions-core-tools` 15 | 3. Azure functions VSCode extension (https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) 16 | 4. Your local dev environment must be setup to use dotnetcore 2.2 17 | 18 | ## Register an AAD App 19 | 20 | The Azure function acts as a WebAPI. 21 | 22 | Register a new app, with the following redirect URIs, 23 | For local testing - 24 | ``` 25 | http://localhost:7071/callback 26 | http://localhost:7071 27 | ``` 28 | 29 | For testing in Azure (this must match your Azure functions URL which you will create later in this tutorial) - 30 | ``` 31 | https://.azurewebsites.net/callback 32 | https://.azurewebsites.net 33 | ``` 34 | Note down it's application id. I will refer to this application id as `client_id_api` for the purposes of this document. 35 | 36 | Also choose to generate a client secret - save it somewhere, you'll need it soon. 37 | 38 | Also save the app id URI of this app. 39 | 40 | Update all these values in the Constants.cs class in your project. 41 | 42 | ## Test your function - locally 43 | 44 | 1. With the project open in VSCode, just hit F5, or you can also run `func host start` from the CLI. 45 | 2. You will need an access token to call this function. In order to get the access token, open browser in private mode and visit 46 | ``` 47 | https://login.microsoftonline.com/.onmicrosoft.com/oauth2/v2.0/authorize?response_type=code&client_id=&redirect_uri=https://localhost:7071/callback&scope=openid 48 | ``` 49 | 50 | This will prompt you to perform authentication, and it will return a code. 51 | Use that code in the following request to get an access token, remember to put in the code and client secret. 52 | 53 | ``` 54 | curl -X POST \ 55 | https://login.microsoftonline.com/.onmicrosoft.com/oauth2/v2.0/token \ 56 | -H 'Accept: */*' \ 57 | -H 'Cache-Control: no-cache' \ 58 | -H 'Connection: keep-alive' \ 59 | -H 'Content-Type: application/x-www-form-urlencoded' \ 60 | -H 'Host: login.microsoftonline.com' \ 61 | -H 'accept-encoding: gzip, deflate' \ 62 | -H 'cache-control: no-cache' \ 63 | -d 'redirect_uri=https%3A%2F%2Flocalhost:7071%2Fcallback&client_id=&grant_type=authorization_code&code=&client_secret=&scope=https%3A%2F%2Fmytestapp..onmicrosoft.com%2F.default' 64 | ``` 65 | 66 | 3. Once you get the access token, make a GET request to `http://localhost:7071/Hello` for the FunctionAttribute project `http://localhost:7071/Authenticated` and with the access token as a Authorization Bearer header. Verify that the output you receive includes the user's name. Modify the access token slightly to make it invalid, Verify that you get HTTP 401 in the Function project, and HTTP 500 in the FunctionAttribute project. 67 | 68 | ## Test your function - in Azure 69 | 70 | 1. Choose to deploy the function 71 | 2. You will need an access token to call this function. In order to get the access token, open browser in private mode and visit 72 | ``` 73 | https://login.microsoftonline.com/.onmicrosoft.com/oauth2/v2.0/authorize?response_type=code&client_id=&redirect_uri=https://.azurewebsites.net/callback&scope=openid 74 | ``` 75 | 76 | This will prompt you to perform authentication, and it will return a code. 77 | Use that code in the following request to get an access token, remember to put in the code and client secret. 78 | 79 | ``` 80 | curl -X POST \ 81 | https://login.microsoftonline.com/.onmicrosoft.com/oauth2/v2.0/token \ 82 | -H 'Accept: */*' \ 83 | -H 'Cache-Control: no-cache' \ 84 | -H 'Connection: keep-alive' \ 85 | -H 'Content-Type: application/x-www-form-urlencoded' \ 86 | -H 'Host: login.microsoftonline.com' \ 87 | -H 'accept-encoding: gzip, deflate' \ 88 | -H 'cache-control: no-cache' \ 89 | -d 'redirect_uri=https%3A%2F%2F.azurewebsites.net%2Fcallback&client_id=&grant_type=authorization_code&code=&client_secret=&scope=https%3A%2F%2Fmytestapp..onmicrosoft.com%2F.default' 90 | ``` 91 | 92 | 3. Once you get the access token, make a GET request to `https://.azurewebsites.net/Hello` for the FunctionAttribute project and `https://.azurewebsites.net/Authenticated` for the function project with the access token as a Authorization Bearer header.Verify that the output you receive includes the user's name. Modify the access token slightly to make it invalid, Verify that you get HTTP 401 in the Function project, and HTTP 500 in the FunctionAttribute project. 93 | 94 | 95 | 96 | -- remove the below later -- 97 | 98 | NLuJ3[l8P39]OVhUCagdqOBr*g*8Op2] 99 | 100 | 101 | https://login.microsoftonline.com/sahilmalikgmail.onmicrosoft.com/oauth2/v2.0/authorize?response_type=code&client_id=d0de483e-2ffc-4847-a51b-39321f038e7f&redirect_uri=http://localhost:7071/callback&scope=openid 102 | 103 | -------------------------------------------------------------------------------- /1. Function/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /2. FunctionAttribute/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | #local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/CallingFunction/.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # Azure Functions localsettings file 5 | local.settings.json 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | bld/ 24 | [Bb]in/ 25 | [Oo]bj/ 26 | [Ll]og/ 27 | 28 | # Visual Studio 2015 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # MSTest test Results 34 | [Tt]est[Rr]esult*/ 35 | [Bb]uild[Ll]og.* 36 | 37 | # NUNIT 38 | *.VisualState.xml 39 | TestResult.xml 40 | 41 | # Build Results of an ATL Project 42 | [Dd]ebugPS/ 43 | [Rr]eleasePS/ 44 | dlldata.c 45 | 46 | # DNX 47 | project.lock.json 48 | project.fragment.lock.json 49 | artifacts/ 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # NCrunch 117 | _NCrunch_* 118 | .*crunch*.local.xml 119 | nCrunchTemp_* 120 | 121 | # MightyMoose 122 | *.mm.* 123 | AutoTest.Net/ 124 | 125 | # Web workbench (sass) 126 | .sass-cache/ 127 | 128 | # Installshield output folder 129 | [Ee]xpress/ 130 | 131 | # DocProject is a documentation generator add-in 132 | DocProject/buildhelp/ 133 | DocProject/Help/*.HxT 134 | DocProject/Help/*.HxC 135 | DocProject/Help/*.hhc 136 | DocProject/Help/*.hhk 137 | DocProject/Help/*.hhp 138 | DocProject/Help/Html2 139 | DocProject/Help/html 140 | 141 | # Click-Once directory 142 | publish/ 143 | 144 | # Publish Web Output 145 | *.[Pp]ublish.xml 146 | *.azurePubxml 147 | # TODO: Comment the next line if you want to checkin your web deploy settings 148 | # but database connection strings (with potential passwords) will be unencrypted 149 | #*.pubxml 150 | *.publishproj 151 | 152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 153 | # checkin your Azure Web App publish settings, but sensitive information contained 154 | # in these scripts will be unencrypted 155 | PublishScripts/ 156 | 157 | # NuGet Packages 158 | *.nupkg 159 | # The packages folder can be ignored because of Package Restore 160 | **/packages/* 161 | # except build/, which is used as an MSBuild target. 162 | !**/packages/build/ 163 | # Uncomment if necessary however generally it will be regenerated when needed 164 | #!**/packages/repositories.config 165 | # NuGet v3's project.json files produces more ignoreable files 166 | *.nuget.props 167 | *.nuget.targets 168 | 169 | # Microsoft Azure Build Output 170 | csx/ 171 | *.build.csdef 172 | 173 | # Microsoft Azure Emulator 174 | ecf/ 175 | rcf/ 176 | 177 | # Windows Store app package directories and files 178 | AppPackages/ 179 | BundleArtifacts/ 180 | Package.StoreAssociation.xml 181 | _pkginfo.txt 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.jfm 196 | *.pfx 197 | *.publishsettings 198 | node_modules/ 199 | orleans.codegen.cs 200 | 201 | # Since there are multiple workflows, uncomment next line to ignore bower_components 202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 203 | #bower_components/ 204 | 205 | # RIA/Silverlight projects 206 | Generated_Code/ 207 | 208 | # Backup & report files from converting an old project file 209 | # to a newer Visual Studio version. Backup files are not needed, 210 | # because we have git ;-) 211 | _UpgradeReport_Files/ 212 | Backup*/ 213 | UpgradeLog*.XML 214 | UpgradeLog*.htm 215 | 216 | # SQL Server files 217 | *.mdf 218 | *.ldf 219 | 220 | # Business Intelligence projects 221 | *.rdl.data 222 | *.bim.layout 223 | *.bim_*.settings 224 | 225 | # Microsoft Fakes 226 | FakesAssemblies/ 227 | 228 | # GhostDoc plugin setting file 229 | *.GhostDoc.xml 230 | 231 | # Node.js Tools for Visual Studio 232 | .ntvs_analysis.dat 233 | 234 | # Visual Studio 6 build log 235 | *.plg 236 | 237 | # Visual Studio 6 workspace options file 238 | *.opt 239 | 240 | # Visual Studio LightSwitch build output 241 | **/*.HTMLClient/GeneratedArtifacts 242 | **/*.DesktopClient/GeneratedArtifacts 243 | **/*.DesktopClient/ModelManifest.xml 244 | **/*.Server/GeneratedArtifacts 245 | **/*.Server/ModelManifest.xml 246 | _Pvt_Extensions 247 | 248 | # Paket dependency manager 249 | .paket/paket.exe 250 | paket-files/ 251 | 252 | # FAKE - F# Make 253 | .fake/ 254 | 255 | # JetBrains Rider 256 | .idea/ 257 | *.sln.iml 258 | 259 | # CodeRush 260 | .cr/ 261 | 262 | # Python Tools for Visual Studio (PTVS) 263 | __pycache__/ 264 | *.pyc -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/armtemplates/calledfunction.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "functionAppName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Specify the name of the function application" 9 | } 10 | }, 11 | "location": { 12 | "type": "string", 13 | "defaultValue": "[resourceGroup().location]", 14 | "metadata": { 15 | "description": "Specify the location for the function application resources" 16 | } 17 | }, 18 | "ApplicationInsightsLocation": { 19 | "type": "string", 20 | "defaultValue": "East US", 21 | "allowedValues": [ 22 | "East US", 23 | "South Central US", 24 | "North Europe", 25 | "West Europe", 26 | "Southeast Asia", 27 | "West US 2", 28 | "Central India", 29 | "Canada Central", 30 | "UK South" 31 | ], 32 | "metadata": { 33 | "description": "Specify the region for Application Insights data" 34 | } 35 | }, 36 | "runtimeStack": { 37 | "type": "string", 38 | "defaultValue": "dotnet", 39 | "allowedValues": [ 40 | "powershell", 41 | "dotnet", 42 | "node", 43 | "java" 44 | ], 45 | "metadata": { 46 | "description": "Pick the language runtime that you want enabled" 47 | } 48 | }, 49 | "timezone": { 50 | "type": "string", 51 | "defaultValue": "UTC", 52 | "allowedValues": [ 53 | "Dateline Standard Time", 54 | "UTC-11", 55 | "Aleutian Standard Time", 56 | "Hawaiian Standard Time", 57 | "Marquesas Standard Time", 58 | "Alaskan Standard Time", 59 | "UTC-09", 60 | "Pacific Standard Time (Mexico)", 61 | "UTC-08", 62 | "Pacific Standard Time", 63 | "US Mountain Standard Time", 64 | "Mountain Standard Time (Mexico)", 65 | "Mountain Standard Time", 66 | "Central America Standard Time", 67 | "Central Standard Time", 68 | "Easter Island Standard Time", 69 | "Central Standard Time (Mexico)", 70 | "Canada Central Standard Time", 71 | "SA Pacific Standard Time", 72 | "Eastern Standard Time (Mexico)", 73 | "Eastern Standard Time", 74 | "Haiti Standard Time", 75 | "Cuba Standard Time", 76 | "US Eastern Standard Time", 77 | "Turks And Caicos Standard Time", 78 | "Paraguay Standard Time", 79 | "Atlantic Standard Time", 80 | "Venezuela Standard Time", 81 | "Central Brazilian Standard Time", 82 | "SA Western Standard Time", 83 | "Pacific SA Standard Time", 84 | "Newfoundland Standard Time", 85 | "Tocantins Standard Time", 86 | "E. South America Standard Time", 87 | "SA Eastern Standard Time", 88 | "Argentina Standard Time", 89 | "Greenland Standard Time", 90 | "Montevideo Standard Time", 91 | "Magallanes Standard Time", 92 | "Saint Pierre Standard Time", 93 | "Bahia Standard Time", 94 | "UTC-02", 95 | "Mid-Atlantic Standard Time", 96 | "Azores Standard Time", 97 | "Cape Verde Standard Time", 98 | "UTC", 99 | "Morocco Standard Time", 100 | "GMT Standard Time", 101 | "Greenwich Standard Time", 102 | "W. Europe Standard Time", 103 | "Central Europe Standard Time", 104 | "Romance Standard Time", 105 | "Sao Tome Standard Time", 106 | "Central European Standard Time", 107 | "W. Central Africa Standard Time", 108 | "Jordan Standard Time", 109 | "GTB Standard Time", 110 | "Middle East Standard Time", 111 | "Egypt Standard Time", 112 | "E. Europe Standard Time", 113 | "Syria Standard Time", 114 | "West Bank Standard Time", 115 | "South Africa Standard Time", 116 | "FLE Standard Time", 117 | "Israel Standard Time", 118 | "Kaliningrad Standard Time", 119 | "Sudan Standard Time", 120 | "Libya Standard Time", 121 | "Namibia Standard Time", 122 | "Arabic Standard Time", 123 | "Turkey Standard Time", 124 | "Arab Standard Time", 125 | "Belarus Standard Time", 126 | "Russian Standard Time", 127 | "E. Africa Standard Time", 128 | "Iran Standard Time", 129 | "Arabian Standard Time", 130 | "Astrakhan Standard Time", 131 | "Azerbaijan Standard Time", 132 | "Russia Time Zone 3", 133 | "Mauritius Standard Time", 134 | "Saratov Standard Time", 135 | "Georgian Standard Time", 136 | "Caucasus Standard Time", 137 | "Afghanistan Standard Time", 138 | "West Asia Standard Time", 139 | "Ekaterinburg Standard Time", 140 | "Pakistan Standard Time", 141 | "India Standard Time", 142 | "Sri Lanka Standard Time", 143 | "Nepal Standard Time", 144 | "Central Asia Standard Time", 145 | "Bangladesh Standard Time", 146 | "Omsk Standard Time", 147 | "Myanmar Standard Time", 148 | "SE Asia Standard Time", 149 | "Altai Standard Time", 150 | "W. Mongolia Standard Time", 151 | "North Asia Standard Time", 152 | "N. Central Asia Standard Time", 153 | "Tomsk Standard Time", 154 | "China Standard Time", 155 | "North Asia East Standard Time", 156 | "Singapore Standard Time", 157 | "W. Australia Standard Time", 158 | "Taipei Standard Time", 159 | "Ulaanbaatar Standard Time", 160 | "Aus Central W. Standard Time", 161 | "Transbaikal Standard Time", 162 | "Tokyo Standard Time", 163 | "North Korea Standard Time", 164 | "Korea Standard Time", 165 | "Yakutsk Standard Time", 166 | "Cen. Australia Standard Time", 167 | "AUS Central Standard Time", 168 | "E. Australia Standard Time", 169 | "AUS Eastern Standard Time", 170 | "West Pacific Standard Time", 171 | "Tasmania Standard Time", 172 | "Vladivostok Standard Time", 173 | "Lord Howe Standard Time", 174 | "Bougainville Standard Time", 175 | "Russia Time Zone 10", 176 | "Magadan Standard Time", 177 | "Norfolk Standard Time", 178 | "Sakhalin Standard Time", 179 | "Central Pacific Standard Time", 180 | "Russia Time Zone 11", 181 | "New Zealand Standard Time", 182 | "UTC+12", 183 | "Fiji Standard Time", 184 | "Kamchatka Standard Time", 185 | "Chatham Islands Standard Time", 186 | "UTC+13", 187 | "Tonga Standard Time", 188 | "Samoa Standard Time", 189 | "Line Islands Standard Time" 190 | ], 191 | "metadata": { 192 | "description": "Pick the timezone to use for the function" 193 | } 194 | } 195 | }, 196 | "variables": { 197 | "hostingPlanName": "[parameters('functionAppName')]", 198 | "storageAccountName": "[concat('storage', uniquestring(resourceGroup().id))]" 199 | }, 200 | "resources": [ 201 | { 202 | "name": "[parameters('functionAppName')]", 203 | "type": "Microsoft.Web/sites", 204 | "apiVersion": "2018-02-01", 205 | "location": "[parameters('location')]", 206 | "kind": "functionapp", 207 | "dependsOn": [ 208 | "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]", 209 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", 210 | "[resourceId('microsoft.insights/components/', parameters('functionAppName'))]" 211 | ], 212 | "properties": { 213 | "siteConfig": { 214 | "appSettings": [ 215 | { 216 | "name": "FUNCTIONS_WORKER_RUNTIME", 217 | "value": "[parameters('runtimeStack')]" 218 | }, 219 | { 220 | "name": "AzureWebJobsStorage", 221 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2017-06-01').keys[0].value)]" 222 | }, 223 | { 224 | "name": "FUNCTIONS_EXTENSION_VERSION", 225 | "value": "~2" 226 | }, 227 | { 228 | "name": "APPINSIGHTS_INSTRUMENTATIONKEY", 229 | "value": "[reference(resourceId('microsoft.insights/components/', parameters('functionAppName')), '2018-05-01-preview').InstrumentationKey]" 230 | }, 231 | { 232 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", 233 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2017-06-01').keys[0].value)]" 234 | }, 235 | { 236 | "name": "WEBSITE_CONTENTSHARE", 237 | "value": "[toLower(parameters('functionAppName'))]" 238 | }, 239 | { 240 | "name": "WEBSITE_TIME_ZONE", 241 | "value": "[parameters('timezone')]" 242 | } 243 | ] 244 | }, 245 | "name": "[parameters('functionAppName')]", 246 | "clientAffinityEnabled": false, 247 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]" 248 | } 249 | }, 250 | { 251 | "type": "Microsoft.Web/serverfarms", 252 | "apiVersion": "2018-11-01", 253 | "name": "[variables('hostingPlanName')]", 254 | "location": "[parameters('location')]", 255 | "properties": { 256 | "name": "[variables('hostingPlanName')]" 257 | }, 258 | "sku": { 259 | "name": "Y1", 260 | "tier": "Dynamic", 261 | "size": "Y1", 262 | "family": "Y", 263 | "capacity": 0 264 | } 265 | }, 266 | { 267 | "apiVersion": "2017-06-01", 268 | "type": "Microsoft.Storage/storageAccounts", 269 | "name": "[variables('storageAccountName')]", 270 | "location": "[parameters('location')]", 271 | "sku": { 272 | "name": "Standard_LRS" 273 | } 274 | }, 275 | { 276 | "apiVersion": "2015-05-01", 277 | "name": "[parameters('functionAppName')]", 278 | "type": "Microsoft.Insights/components", 279 | "location": "[parameters('ApplicationInsightsLocation')]", 280 | "kind": "other", 281 | "tags": { 282 | "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('functionAppName')))]": "Resource" 283 | }, 284 | "properties": { 285 | "ApplicationId": "[parameters('functionAppName')]", 286 | "Application_Type":"other" 287 | } 288 | } 289 | ] 290 | } -------------------------------------------------------------------------------- /3. ManagedIdentityFunctionCallingAnotherFunction/armtemplates/callingfunction.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "identityName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "user-assigned managed identity" 9 | } 10 | }, 11 | "functionAppName": { 12 | "type": "string", 13 | "metadata": { 14 | "description": "Specify the name of the function application" 15 | } 16 | }, 17 | "location": { 18 | "type": "string", 19 | "defaultValue": "[resourceGroup().location]", 20 | "metadata": { 21 | "description": "Specify the location for the function application resources" 22 | } 23 | }, 24 | "ApplicationInsightsLocation": { 25 | "type": "string", 26 | "defaultValue": "East US", 27 | "allowedValues": [ 28 | "East US", 29 | "South Central US", 30 | "North Europe", 31 | "West Europe", 32 | "Southeast Asia", 33 | "West US 2", 34 | "Central India", 35 | "Canada Central", 36 | "UK South" 37 | ], 38 | "metadata": { 39 | "description": "Specify the region for Application Insights data" 40 | } 41 | }, 42 | "runtimeStack": { 43 | "type": "string", 44 | "defaultValue": "dotnet", 45 | "allowedValues": [ 46 | "powershell", 47 | "dotnet", 48 | "node", 49 | "java" 50 | ], 51 | "metadata": { 52 | "description": "Pick the language runtime that you want enabled" 53 | } 54 | }, 55 | "timezone": { 56 | "type": "string", 57 | "defaultValue": "UTC", 58 | "allowedValues": [ 59 | "Dateline Standard Time", 60 | "UTC-11", 61 | "Aleutian Standard Time", 62 | "Hawaiian Standard Time", 63 | "Marquesas Standard Time", 64 | "Alaskan Standard Time", 65 | "UTC-09", 66 | "Pacific Standard Time (Mexico)", 67 | "UTC-08", 68 | "Pacific Standard Time", 69 | "US Mountain Standard Time", 70 | "Mountain Standard Time (Mexico)", 71 | "Mountain Standard Time", 72 | "Central America Standard Time", 73 | "Central Standard Time", 74 | "Easter Island Standard Time", 75 | "Central Standard Time (Mexico)", 76 | "Canada Central Standard Time", 77 | "SA Pacific Standard Time", 78 | "Eastern Standard Time (Mexico)", 79 | "Eastern Standard Time", 80 | "Haiti Standard Time", 81 | "Cuba Standard Time", 82 | "US Eastern Standard Time", 83 | "Turks And Caicos Standard Time", 84 | "Paraguay Standard Time", 85 | "Atlantic Standard Time", 86 | "Venezuela Standard Time", 87 | "Central Brazilian Standard Time", 88 | "SA Western Standard Time", 89 | "Pacific SA Standard Time", 90 | "Newfoundland Standard Time", 91 | "Tocantins Standard Time", 92 | "E. South America Standard Time", 93 | "SA Eastern Standard Time", 94 | "Argentina Standard Time", 95 | "Greenland Standard Time", 96 | "Montevideo Standard Time", 97 | "Magallanes Standard Time", 98 | "Saint Pierre Standard Time", 99 | "Bahia Standard Time", 100 | "UTC-02", 101 | "Mid-Atlantic Standard Time", 102 | "Azores Standard Time", 103 | "Cape Verde Standard Time", 104 | "UTC", 105 | "Morocco Standard Time", 106 | "GMT Standard Time", 107 | "Greenwich Standard Time", 108 | "W. Europe Standard Time", 109 | "Central Europe Standard Time", 110 | "Romance Standard Time", 111 | "Sao Tome Standard Time", 112 | "Central European Standard Time", 113 | "W. Central Africa Standard Time", 114 | "Jordan Standard Time", 115 | "GTB Standard Time", 116 | "Middle East Standard Time", 117 | "Egypt Standard Time", 118 | "E. Europe Standard Time", 119 | "Syria Standard Time", 120 | "West Bank Standard Time", 121 | "South Africa Standard Time", 122 | "FLE Standard Time", 123 | "Israel Standard Time", 124 | "Kaliningrad Standard Time", 125 | "Sudan Standard Time", 126 | "Libya Standard Time", 127 | "Namibia Standard Time", 128 | "Arabic Standard Time", 129 | "Turkey Standard Time", 130 | "Arab Standard Time", 131 | "Belarus Standard Time", 132 | "Russian Standard Time", 133 | "E. Africa Standard Time", 134 | "Iran Standard Time", 135 | "Arabian Standard Time", 136 | "Astrakhan Standard Time", 137 | "Azerbaijan Standard Time", 138 | "Russia Time Zone 3", 139 | "Mauritius Standard Time", 140 | "Saratov Standard Time", 141 | "Georgian Standard Time", 142 | "Caucasus Standard Time", 143 | "Afghanistan Standard Time", 144 | "West Asia Standard Time", 145 | "Ekaterinburg Standard Time", 146 | "Pakistan Standard Time", 147 | "India Standard Time", 148 | "Sri Lanka Standard Time", 149 | "Nepal Standard Time", 150 | "Central Asia Standard Time", 151 | "Bangladesh Standard Time", 152 | "Omsk Standard Time", 153 | "Myanmar Standard Time", 154 | "SE Asia Standard Time", 155 | "Altai Standard Time", 156 | "W. Mongolia Standard Time", 157 | "North Asia Standard Time", 158 | "N. Central Asia Standard Time", 159 | "Tomsk Standard Time", 160 | "China Standard Time", 161 | "North Asia East Standard Time", 162 | "Singapore Standard Time", 163 | "W. Australia Standard Time", 164 | "Taipei Standard Time", 165 | "Ulaanbaatar Standard Time", 166 | "Aus Central W. Standard Time", 167 | "Transbaikal Standard Time", 168 | "Tokyo Standard Time", 169 | "North Korea Standard Time", 170 | "Korea Standard Time", 171 | "Yakutsk Standard Time", 172 | "Cen. Australia Standard Time", 173 | "AUS Central Standard Time", 174 | "E. Australia Standard Time", 175 | "AUS Eastern Standard Time", 176 | "West Pacific Standard Time", 177 | "Tasmania Standard Time", 178 | "Vladivostok Standard Time", 179 | "Lord Howe Standard Time", 180 | "Bougainville Standard Time", 181 | "Russia Time Zone 10", 182 | "Magadan Standard Time", 183 | "Norfolk Standard Time", 184 | "Sakhalin Standard Time", 185 | "Central Pacific Standard Time", 186 | "Russia Time Zone 11", 187 | "New Zealand Standard Time", 188 | "UTC+12", 189 | "Fiji Standard Time", 190 | "Kamchatka Standard Time", 191 | "Chatham Islands Standard Time", 192 | "UTC+13", 193 | "Tonga Standard Time", 194 | "Samoa Standard Time", 195 | "Line Islands Standard Time" 196 | ], 197 | "metadata": { 198 | "description": "Pick the timezone to use for the function" 199 | } 200 | } 201 | }, 202 | "variables": { 203 | "hostingPlanName": "[parameters('functionAppName')]", 204 | "storageAccountName": "[concat('storage', uniquestring(resourceGroup().id))]" 205 | }, 206 | "resources": [ 207 | { 208 | "name": "[parameters('functionAppName')]", 209 | "type": "Microsoft.Web/sites", 210 | "identity": { 211 | "type": "UserAssigned", 212 | "userAssignedIdentities": { 213 | "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]": {} 214 | } 215 | }, 216 | "apiVersion": "2018-02-01", 217 | "location": "[parameters('location')]", 218 | "kind": "functionapp", 219 | "dependsOn": [ 220 | "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]", 221 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]", 222 | "[resourceId('microsoft.insights/components/', parameters('functionAppName'))]" 223 | ], 224 | "properties": { 225 | "siteConfig": { 226 | "appSettings": [ 227 | { 228 | "name": "FUNCTIONS_WORKER_RUNTIME", 229 | "value": "[parameters('runtimeStack')]" 230 | }, 231 | { 232 | "name": "AzureWebJobsStorage", 233 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2017-06-01').keys[0].value)]" 234 | }, 235 | { 236 | "name": "FUNCTIONS_EXTENSION_VERSION", 237 | "value": "~2" 238 | }, 239 | { 240 | "name": "APPINSIGHTS_INSTRUMENTATIONKEY", 241 | "value": "[reference(resourceId('microsoft.insights/components/', parameters('functionAppName')), '2018-05-01-preview').InstrumentationKey]" 242 | }, 243 | { 244 | "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", 245 | "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2017-06-01').keys[0].value)]" 246 | }, 247 | { 248 | "name": "WEBSITE_CONTENTSHARE", 249 | "value": "[toLower(parameters('functionAppName'))]" 250 | }, 251 | { 252 | "name": "WEBSITE_TIME_ZONE", 253 | "value": "[parameters('timezone')]" 254 | } 255 | ] 256 | }, 257 | "name": "[parameters('functionAppName')]", 258 | "clientAffinityEnabled": false, 259 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]" 260 | } 261 | }, 262 | { 263 | "type": "Microsoft.Web/serverfarms", 264 | "apiVersion": "2018-11-01", 265 | "name": "[variables('hostingPlanName')]", 266 | "location": "[parameters('location')]", 267 | "properties": { 268 | "name": "[variables('hostingPlanName')]" 269 | }, 270 | "sku": { 271 | "name": "Y1", 272 | "tier": "Dynamic", 273 | "size": "Y1", 274 | "family": "Y", 275 | "capacity": 0 276 | } 277 | }, 278 | { 279 | "apiVersion": "2017-06-01", 280 | "type": "Microsoft.Storage/storageAccounts", 281 | "name": "[variables('storageAccountName')]", 282 | "location": "[parameters('location')]", 283 | "sku": { 284 | "name": "Standard_LRS" 285 | } 286 | }, 287 | { 288 | "apiVersion": "2015-05-01", 289 | "name": "[parameters('functionAppName')]", 290 | "type": "Microsoft.Insights/components", 291 | "location": "[parameters('ApplicationInsightsLocation')]", 292 | "kind": "other", 293 | "tags": { 294 | "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('functionAppName')))]": "Resource" 295 | }, 296 | "properties": { 297 | "ApplicationId": "[parameters('functionAppName')]", 298 | "Application_Type":"other" 299 | } 300 | } 301 | ] 302 | } --------------------------------------------------------------------------------