Skip to content

Commit 524e167

Browse files
committed
Fix claims for SI and SRE users
1 parent 4d69ae7 commit 524e167

File tree

5 files changed

+126
-12
lines changed

5 files changed

+126
-12
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ The application requires authentication. See https://altinn.github.io/docs/api/r
2828
#### Legacy (Altinn 2) Enterprise user tokens (aka Maskinporten + Enterprise user authentication):
2929
`https://altinn-testtools-token-generator.azurewebsites.net/api/GetEnterpriseUserToken?env={environment}&orgNo={orgNo}&partyId={partyId}&userId={userId}&userName={userName}`
3030

31+
#### Legacy (Altinn 2) self-identified user tokens
32+
`https://altinn-testtools-token-generator.azurewebsites.net/api/GetSelfIdentifiedUserToken?env={environment}&orgNo={orgNo}&partyId={partyId}&userId={userId}&userName={userName}`
33+
34+
#### ID-porten self-registered email user tokens
35+
`https://altinn-testtools-token-generator.azurewebsites.net/api/GetSelfRegisteredEmailUserToken?env={environment}&orgNo={orgNo}&partyId={partyId}&userId={userId}&email={email}`
36+
37+
3138
#### Optional parameters:
3239

3340
* `supplierOrgNo` (Enterprise tokens only)

TokenGenerator/GetSelfIdentifiedUserToken.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public async Task<ActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "
4141
requestValidator.ValidateQueryParam("partyId", false, uint.TryParse, out uint partyId, (uint)rnd.Next(5000000, 7000000));
4242
requestValidator.ValidateQueryParam("partyuuid", false, Guid.TryParse, out Guid partyUuid, Guid.NewGuid());
4343
requestValidator.ValidateQueryParam("username", false, tokenHelper.IsValidIdentifier, out string username, $"SIUser{rnd.Next(1000, 9999)}");
44-
requestValidator.ValidateQueryParam("email", true, tokenHelper.IsValidEmail, out string email);
4544

4645
requestValidator.ValidateQueryParam<uint>("ttl", false, uint.TryParse, out uint ttl, 1800);
4746

@@ -50,7 +49,7 @@ public async Task<ActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "
5049
return new BadRequestObjectResult(requestValidator.GetErrors());
5150
}
5251

53-
string token = await tokenHelper.GeSelfIdentifiedUserToken(env, scopes, userId, partyId, partyUuid, username, email, ttl);
52+
string token = await tokenHelper.GetSelfIdentifiedUserToken(env, scopes, userId, partyId, partyUuid, username, ttl);
5453

5554
if (!string.IsNullOrEmpty(req.Query["dump"]))
5655
{
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.Azure.WebJobs;
4+
using Microsoft.Azure.WebJobs.Extensions.Http;
5+
using Microsoft.AspNetCore.Http;
6+
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Options;
8+
using TokenGenerator.Services.Interfaces;
9+
10+
namespace TokenGenerator
11+
{
12+
public class GetSelfRegisteredEmailUserToken
13+
{
14+
private readonly IToken tokenHelper;
15+
private readonly IRequestValidator requestValidator;
16+
private readonly IAuthorization authorization;
17+
private readonly Settings settings;
18+
19+
public GetSelfRegisteredEmailUserToken(IToken tokenHelper, IRequestValidator requestValidator, IAuthorization authorization, IOptions<Settings> settings)
20+
{
21+
this.tokenHelper = tokenHelper;
22+
this.requestValidator = requestValidator;
23+
this.authorization = authorization;
24+
this.settings = settings.Value;
25+
}
26+
27+
[FunctionName(nameof(GetSelfRegisteredEmailUserToken))]
28+
public async Task<ActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req)
29+
{
30+
ActionResult failedAuthorizationResult = await authorization.Authorize(settings.AuthorizedScopePersonal);
31+
if (failedAuthorizationResult != null)
32+
{
33+
return failedAuthorizationResult;
34+
}
35+
36+
var rnd = new Random();
37+
38+
requestValidator.ValidateQueryParam("env", true, tokenHelper.IsValidEnvironment, out string env);
39+
requestValidator.ValidateQueryParam("userId", false, uint.TryParse, out uint userId);
40+
requestValidator.ValidateQueryParam("scopes", false, tokenHelper.TryParseScopes, out string[] scopes, new[] { "altinn:portal/enduser" });
41+
requestValidator.ValidateQueryParam("partyId", false, uint.TryParse, out uint partyId, (uint)rnd.Next(5000000, 7000000));
42+
requestValidator.ValidateQueryParam("partyuuid", false, Guid.TryParse, out Guid partyUuid, Guid.NewGuid());
43+
requestValidator.ValidateQueryParam("email", true, tokenHelper.IsValidEmail, out string email);
44+
45+
requestValidator.ValidateQueryParam<uint>("ttl", false, uint.TryParse, out uint ttl, 1800);
46+
47+
if (requestValidator.GetErrors().Count > 0)
48+
{
49+
return new BadRequestObjectResult(requestValidator.GetErrors());
50+
}
51+
52+
string token = await tokenHelper.GetSelfRegisteredEmailUserToken(env, scopes, userId, partyId, partyUuid, email, ttl);
53+
54+
if (!string.IsNullOrEmpty(req.Query["dump"]))
55+
{
56+
return new OkObjectResult(tokenHelper.Dump(token));
57+
}
58+
59+
return new OkObjectResult(token);
60+
}
61+
}
62+
}

TokenGenerator/Services/Interfaces/IToken.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public interface IToken
1414
Task<string> GetConsentToken(string env, string[] serviceCodes, IQueryCollection queryParameters, Guid authorizationCode, string offeredBy, string coveredBy, string handledBy, uint ttl);
1515
Task<string> GetPlatformToken(string env, string appClaim, uint ttl);
1616
Task<string> GetPlatformAccessToken(string env, string appClaim, uint ttl, string iss = "platform");
17-
Task<string> GeSelfIdentifiedUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string userName, string email, uint ttl);
17+
Task<string> GetSelfIdentifiedUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string userName, uint ttl);
18+
Task<string> GetSelfRegisteredEmailUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string email, uint ttl);
1819
Task<Dictionary<string, string>> GetTokenList(List<string> claimValues, Func<string, Task<string>> getToken);
1920

2021
string Dump(string token);

TokenGenerator/Services/Token.cs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -314,30 +314,75 @@ public async Task<string> GetPlatformAccessToken(string env, string appClaim, ui
314314
throw new ArgumentException("Invalid issuer");
315315
}
316316

317-
public async Task<string> GeSelfIdentifiedUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string userName, string email, uint ttl)
317+
public async Task<string> GetSelfIdentifiedUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string userName, uint ttl)
318318
{
319319
var header = await GetJwtHeader(env);
320320
var dateTimeOffset = new DateTimeOffset(DateTime.UtcNow);
321+
var sidJti = RandomString(43);
322+
323+
// https://github.com/Altinn/dialogporten/issues/3362#issuecomment-3834123082
321324
var payload = new JwtPayload
322325
{
323-
// NOTE! This is an interim solution until the full list of claims is defined.
324-
{ "nameid", (int)userId },
326+
{ "sub", partyUuid.ToString() },
327+
{ "sid", sidJti },
328+
{ "iss", GetIssuer(null, env) },
329+
{ "urn:altinn:party:uuid", partyUuid.ToString() },
330+
{ "jti", sidJti },
331+
{ "urn:altinn:partyid", (int)partyId },
325332
{ "urn:altinn:userid", (int)userId },
326333
{ "urn:altinn:username", userName },
334+
{ "orignaliss", "altinn2" },
335+
{ "acr", "idporten-loa-low" },
336+
{ "urn:altinn:authlevel", 0 },
337+
{ "amr", new[] { "SelfIdentified" } },
338+
{ "urn:altinn:authenticatemethod", "SelfIdentified" },
339+
{ "scope", string.Join(' ', scopes) },
340+
{ "nbf", dateTimeOffset.ToUnixTimeSeconds() },
341+
{ "exp", dateTimeOffset.ToUnixTimeSeconds() + ttl },
342+
{ "iat", dateTimeOffset.ToUnixTimeSeconds() },
343+
344+
{ "actual_iss", "altinn-test-tools" },
345+
346+
};
347+
348+
var securityToken = new JwtSecurityToken(header, payload);
349+
var handler = new JwtSecurityTokenHandler();
350+
351+
return handler.WriteToken(securityToken);
352+
}
353+
354+
public async Task<string> GetSelfRegisteredEmailUserToken(string env, string[] scopes, uint userId, uint partyId, Guid partyUuid, string email, uint ttl)
355+
{
356+
var header = await GetJwtHeader(env);
357+
var dateTimeOffset = new DateTimeOffset(DateTime.UtcNow);
358+
var sidJti = RandomString(43);
359+
360+
// https://github.com/Altinn/dialogporten/issues/3362#issuecomment-3834123082
361+
var payload = new JwtPayload
362+
{
363+
{ "sub", partyUuid.ToString() },
364+
{ "sid", sidJti },
365+
{ "iss", GetIssuer(null, env) },
327366
{ "urn:altinn:party:uuid", partyUuid.ToString() },
367+
{ "jti", sidJti },
328368
{ "urn:altinn:partyid", (int)partyId },
329-
{ "urn:altinn:authenticatemethod", "SelfIdentified" },
369+
{ "urn:altinn:userid", (int)userId },
370+
{ "urn:altinn:username", "epost:" + email },
371+
{ "orignaliss", "idporten" },
372+
{ "email", email },
373+
{ "urn:altinn:party:external-identifer", "urn:altinn:person:idporten-email:" + email },
374+
{ "acr", "selfregistered-email" },
330375
{ "urn:altinn:authlevel", 0 },
331-
{ "jti", RandomString(43) },
376+
{ "amr", new[] { "Selfregistered-email" } },
377+
{ "urn:altinn:authenticatemethod", "IdportenEpost" },
378+
{ "auth_time", dateTimeOffset.ToUnixTimeSeconds() },
332379
{ "scope", string.Join(' ', scopes) },
333380
{ "nbf", dateTimeOffset.ToUnixTimeSeconds() },
334381
{ "exp", dateTimeOffset.ToUnixTimeSeconds() + ttl },
335382
{ "iat", dateTimeOffset.ToUnixTimeSeconds() },
336-
{ "iss", GetIssuer(null, env) },
383+
337384
{ "actual_iss", "altinn-test-tools" },
338-
// These are the salient claims from https://docs.digdir.no/docs/idporten/oidc/oidc_func_emaillogin.html
339-
{ "arm", new[] { "Selfregistered-email" } },
340-
{ "email", email }
385+
341386
};
342387

343388
var securityToken = new JwtSecurityToken(header, payload);

0 commit comments

Comments
 (0)