Skip to content

Commit 2a75d56

Browse files
Add custom key-based authentication to HTTP triggers (#12)
Related to #10 Add custom key-based authentication to HTTP triggers. * **README.md**: Add instructions for setting up custom key-based authentication. * **BaseHttpTrigger.cs**: Add `ValidateCustomKey` method to perform custom key-based authentication. Update `Authorize` method to accept a custom key and validate it using `ValidateCustomKey`. * **UserDetailsTrigger.cs**: Update `Run` method to use `AuthorizationLevel.Function` and pass a custom key to the `Authorize` method. * **HealthCheckTrigger.cs**: Update `Run` method to use `AuthorizationLevel.Function` and pass a custom key to the `Authorize` method. Add custom key validation in the `Run` method. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/palkalaiselvand/Azure_HTTPTriggerFunctionSample/issues/10?shareId=XXXX-XXXX-XXXX-XXXX).
1 parent 8d656d3 commit 2a75d56

File tree

4 files changed

+92
-11
lines changed

4 files changed

+92
-11
lines changed

README.md

+67-1
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,70 @@ Azure_HTTPTriggerFunctionSample
9393
"EmailAddress": "[email protected]",
9494
"Department": "Information Technology"
9595
}
96-
96+
97+
### Custom Key-based Authentication
98+
99+
To set up custom key-based authentication, follow these steps:
100+
101+
1. Add a custom key to your `local.settings.json` file:
102+
103+
```json
104+
{
105+
"IsEncrypted": false,
106+
"Values": {
107+
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
108+
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
109+
"SampleApp_ConnectionString": "Data Source=(localdb)\\ProjectsV13;Initial Catalog=SampleApp;Integrated Security=True;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
110+
"SampleApp_ServiceBus_ConnectionString": "Endpoint=sb://developmentaccount.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=2m+dy8rXboZmHrDdqkDod46Hg/DThH9aYEM1ZYFWUpo=",
111+
"SampleApp_ServiceBus_QueueName": "sbuserdetailsqueue",
112+
"SampleApp_ServiceBus_TopicName": "sbuserdetailstopic",
113+
"SampleApp_StorageAccount_ConnectionString": "DefaultEndpointsProtocol=https;AccountName=storaccpocctr;AccountKey=SzlfpjbTy+VpR0DqJHt6Wb4/TP1MEPV0eIsjHepxSxXQ5e3RitFTwwz5clAxWxXAloNO2Hc2yZvePHks65I/qg==;EndpointSuffix=core.windows.net",
114+
"SampleApp_StorageQueueName": "squserdetailsqueue",
115+
"AzureQueueAssets": "ServiceBus|Queue",
116+
"CustomAuthKey": "your-custom-key"
117+
}
118+
}
119+
```
120+
121+
2. Update your HTTP trigger functions to use the custom key for authentication. For example, in `UserDetailsTrigger.cs`, pass the custom key to the `Authorize` method:
122+
123+
```csharp
124+
[FunctionName(nameof(UserDetailsTrigger))]
125+
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "v1/userdetails")] HttpRequest req,
126+
ILogger logger)
127+
{
128+
string customKey = req.Headers["CustomAuthKey"];
129+
return await Request(req, logger)
130+
.Authorize(AuthorizationLevel.Function, customKey)
131+
.Run(Work);
132+
}
133+
```
134+
135+
3. Implement the `ValidateCustomKey` method in `BaseHttpTrigger.cs` to perform custom key-based authentication:
136+
137+
```csharp
138+
public class BaseHttpTrigger
139+
{
140+
// Existing code...
141+
142+
public bool ValidateCustomKey(string customKey)
143+
{
144+
string expectedKey = Environment.GetEnvironmentVariable("CustomAuthKey");
145+
return customKey == expectedKey;
146+
}
147+
}
148+
```
149+
150+
4. Update the `Authorize` method in `BaseHttpTrigger.cs` to accept a custom key and validate it using `ValidateCustomKey`:
151+
152+
```csharp
153+
public RequestContext Authorize(AuthorizationLevel authorizationLevel, string customKey)
154+
{
155+
_authorizationLevel = authorizationLevel;
156+
if (!ValidateCustomKey(customKey))
157+
{
158+
throw new UnauthorizedAccessException("Invalid custom key");
159+
}
160+
return this;
161+
}
162+
```

SampleFunctionApp/HttpTrigger/BaseHttpTrigger.cs

+15-7
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,47 @@ public RequestContext Request(HttpRequest req, ILogger logger)
1515
{
1616
return new RequestContext(req, logger);
1717
}
18+
19+
public bool ValidateCustomKey(string customKey)
20+
{
21+
string expectedKey = Environment.GetEnvironmentVariable("CustomAuthKey");
22+
return customKey == expectedKey;
23+
}
1824
}
1925

2026
public class RequestContext
2127
{
2228
private readonly HttpRequest _httpRequest;
2329
private readonly ILogger _logger;
2430
private AuthorizationLevel _authorizationLevel;
31+
private string _customKey;
32+
2533
public RequestContext(HttpRequest httpRequest, ILogger logger)
2634
{
2735
_httpRequest = httpRequest;
2836
_logger = logger;
2937
}
3038

31-
public RequestContext Authorize(AuthorizationLevel authorizationLevel)
39+
public RequestContext Authorize(AuthorizationLevel authorizationLevel, string customKey)
3240
{
33-
//TODO: Load required data to perform authenticationa nd authorization
34-
// For now just to have a place holder I created this
3541
_authorizationLevel = authorizationLevel;
42+
_customKey = customKey;
43+
if (!new BaseHttpTrigger().ValidateCustomKey(customKey))
44+
{
45+
throw new UnauthorizedAccessException("Invalid custom key");
46+
}
3647
return this;
3748
}
3849

3950
public async Task<IActionResult> Run(Func<HttpRequest, ILogger, Task<IActionResult>> func)
4051
{
4152
try
4253
{
43-
//TODO: Perform custom authentication and authorization logic
44-
// For now just to have a place holder I created this
45-
if (_authorizationLevel != AuthorizationLevel.Anonymous)
54+
if (_authorizationLevel != AuthorizationLevel.Anonymous && !new BaseHttpTrigger().ValidateCustomKey(_customKey))
4655
{
4756
return new ForbidResult();
4857
}
4958

50-
//Call the actual WORK method to perform the task
5159
return await func(_httpRequest, _logger);
5260
}
5361
catch (Exception ex)

SampleFunctionApp/HttpTrigger/HealthCheckTrigger.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ public static class HealthCheckTrigger
1111
{
1212
[FunctionName("HealthCheckTrigger")]
1313
public static async Task<IActionResult> Run(
14-
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
14+
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
1515
ILogger log)
1616
{
1717
log.LogInformation("HealthCheckTrigger function processed a request.");
1818

19+
string customKey = req.Headers["CustomAuthKey"];
20+
if (!new BaseHttpTrigger().ValidateCustomKey(customKey))
21+
{
22+
return new UnauthorizedResult();
23+
}
24+
1925
return new OkObjectResult("App is healthy");
2026
}
2127
}

SampleFunctionApp/HttpTrigger/UserDetailsTrigger.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ public UserDetailsTrigger(IRequestAuditRepository audit,
3737
_storageQueue = storageQueue;
3838
}
3939
[FunctionName(nameof(UserDetailsTrigger))]
40-
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "v1/userdetails")] HttpRequest req,
40+
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "v1/userdetails")] HttpRequest req,
4141
ILogger logger)
4242
{
43+
string customKey = req.Headers["CustomAuthKey"];
4344
return await Request(req, logger)
44-
.Authorize(AuthorizationLevel.Anonymous)
45+
.Authorize(AuthorizationLevel.Function, customKey)
4546
.Run(Work);
4647
}
4748

0 commit comments

Comments
 (0)