Skip to content

Commit d8c2a65

Browse files
Remove self identified users as a special case in Authenticated (#1241)
1 parent 63ea12b commit d8c2a65

22 files changed

+127
-260
lines changed

src/Altinn.App.Api/Controllers/ActionsController.cs

-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ public async Task<ActionResult<UserActionResponse>> Perform(
109109
{
110110
case Authenticated.User:
111111
case Authenticated.SystemUser:
112-
case Authenticated.SelfIdentifiedUser:
113112
break;
114113
default:
115114
return Unauthorized();

src/Altinn.App.Api/Controllers/AuthorizationController.cs

-10
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,6 @@ public async Task<ActionResult> GetCurrentParty(bool returnPartyObject = false)
7979
}
8080
return Ok(reportee.PartyId);
8181
}
82-
case Authenticated.SelfIdentifiedUser selfIdentified:
83-
{
84-
var details = await selfIdentified.LoadDetails();
85-
if (returnPartyObject)
86-
{
87-
return Ok(details.Party);
88-
}
89-
90-
return Ok(details.Party.PartyId);
91-
}
9282
case Authenticated.Org org:
9383
{
9484
var details = await org.LoadDetails();

src/Altinn.App.Api/Controllers/PartiesController.cs

-47
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ public async Task<IActionResult> Get(string org, string app, bool allowedToInsta
4949
var details = await user.LoadDetails(validateSelectedParty: false);
5050
return allowedToInstantiateFilter ? Ok(details.PartiesAllowedToInstantiate) : Ok(details.Parties);
5151
}
52-
case Authenticated.SelfIdentifiedUser selfIdentified:
53-
{
54-
var details = await selfIdentified.LoadDetails();
55-
IReadOnlyList<Party> parties = [details.Party];
56-
return Ok(parties);
57-
}
5852
case Authenticated.Org orgInfo:
5953
{
6054
var details = await orgInfo.LoadDetails();
@@ -123,34 +117,6 @@ public async Task<IActionResult> ValidateInstantiation(string org, string app, [
123117

124118
return Ok(new InstantiationValidationResult { Valid = true });
125119
}
126-
case Authenticated.SelfIdentifiedUser auth:
127-
{
128-
var details = await auth.LoadDetails();
129-
if (details.Party.PartyId != partyId)
130-
{
131-
return Ok(
132-
new InstantiationValidationResult
133-
{
134-
Valid = false,
135-
Message = "The user does not represent the supplied party",
136-
ValidParties = new List<Party> { details.Party },
137-
}
138-
);
139-
}
140-
if (!details.CanInstantiate)
141-
{
142-
return Ok(
143-
new InstantiationValidationResult
144-
{
145-
Valid = false,
146-
Message = "The supplied party is not allowed to instantiate the application",
147-
ValidParties = new List<Party> { details.Party },
148-
}
149-
);
150-
}
151-
152-
return Ok(new InstantiationValidationResult { Valid = true });
153-
}
154120
case Authenticated.Org auth:
155121
{
156122
var details = await auth.LoadDetails();
@@ -241,19 +207,6 @@ public async Task<IActionResult> UpdateSelectedParty(int partyId)
241207

242208
return Ok("Party successfully updated");
243209
}
244-
case Authenticated.SelfIdentifiedUser auth:
245-
{
246-
if (auth.PartyId != partyId)
247-
return BadRequest($"User {auth.UserId} cannot represent party {partyId}.");
248-
249-
Response.Cookies.Append(
250-
_settings.GetAltinnPartyCookieName,
251-
partyId.ToString(CultureInfo.InvariantCulture),
252-
new CookieOptions { Domain = _settings.HostName }
253-
);
254-
255-
return Ok("Party successfully updated");
256-
}
257210
case Authenticated.Org auth:
258211
{
259212
var details = await auth.LoadDetails();

src/Altinn.App.Api/Controllers/ProfileController.cs

-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@ public async Task<ActionResult> GetUser()
3737
var details = await user.LoadDetails(validateSelectedParty: false);
3838
return Ok(details.Profile);
3939
}
40-
case Authenticated.SelfIdentifiedUser selfIdentifiedUser:
41-
{
42-
var details = await selfIdentifiedUser.LoadDetails();
43-
return Ok(details.Profile);
44-
}
4540
default:
4641
return BadRequest($"Unknown authentication context: {context.GetType().Name}");
4742
}

src/Altinn.App.Api/Controllers/StatelessDataController.cs

-1
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,6 @@ public async Task<ActionResult> PostAnonymous([FromQuery] string dataType, [From
347347
Party? party = currentAuth switch
348348
{
349349
Authenticated.User auth => await auth.LookupSelectedParty(),
350-
Authenticated.SelfIdentifiedUser auth => (await auth.LoadDetails()).Party,
351350
Authenticated.Org auth => (await auth.LoadDetails()).Party,
352351
Authenticated.ServiceOwner auth => (await auth.LoadDetails()).Party,
353352
Authenticated.SystemUser auth => (await auth.LoadDetails()).Party,

src/Altinn.App.Core/Features/Action/SigningUserAction.cs

+1-8
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,7 @@ IAppMetadata appMetadata
5151
/// <exception cref="ApplicationConfigException"></exception>
5252
public async Task<UserActionResult> HandleAction(UserActionContext context)
5353
{
54-
if (
55-
context.Authentication
56-
is not Authenticated.User
57-
and not Authenticated.SelfIdentifiedUser
58-
and not Authenticated.SystemUser
59-
)
54+
if (context.Authentication is not Authenticated.User and not Authenticated.SystemUser)
6055
{
6156
return UserActionResult.FailureResult(
6257
error: new ActionError() { Code = "NoUserId", Message = "User id is missing in token" },
@@ -157,8 +152,6 @@ private static async Task<Signee> GetSignee(UserActionContext context)
157152
OrganisationNumber = userProfile.Party.OrgNumber,
158153
};
159154
}
160-
case Authenticated.SelfIdentifiedUser selfIdentifiedUser:
161-
return new Signee { UserId = selfIdentifiedUser.UserId.ToString(CultureInfo.InvariantCulture) };
162155
case Authenticated.SystemUser systemUser:
163156
return new Signee
164157
{

src/Altinn.App.Core/Features/Action/UniqueSignatureAuthorizer.cs

-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ public async Task<bool> AuthorizeAction(UserActionAuthorizerContext context)
8383
bool unauthorized = context.Authentication switch
8484
{
8585
Authenticated.User a => a.UserId.ToString(CultureInfo.InvariantCulture) == signee?.UserId,
86-
Authenticated.SelfIdentifiedUser a => a.UserId.ToString(CultureInfo.InvariantCulture)
87-
== signee?.UserId,
8886
Authenticated.SystemUser a => a.SystemUserId[0] == signee?.SystemUserId,
8987
_ => false,
9088
};

src/Altinn.App.Core/Features/Auth/Authenticated.cs

+41-110
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,12 @@ public async Task<string> GetLanguage()
5858
{
5959
string language = LanguageConst.Nb;
6060

61-
if (this is not User and not SelfIdentifiedUser)
61+
if (this is not User)
6262
return language;
6363

6464
var profile = this switch
6565
{
6666
User user => await user.LookupProfile(),
67-
SelfIdentifiedUser selfIdentifiedUser => (await selfIdentifiedUser.LoadDetails()).Profile,
6867
_ => throw new InvalidOperationException($"Unexpected case: {this.GetType().Name}"),
6968
};
7069

@@ -93,13 +92,23 @@ public sealed class User : Authenticated
9392
/// </summary>
9493
public int UserId { get; }
9594

95+
/// <summary>
96+
/// Username of the registered user, only relevant for self-identified/self-registered users.
97+
/// E.g. BankID doesn't operate based on usernames, so this property would be null in that case.
98+
/// </summary>
99+
public string? Username { get; }
100+
96101
/// <summary>
97102
/// Party ID
98103
/// </summary>
99104
public int UserPartyId { get; }
100105

101106
/// <summary>
102107
/// The party the user has selected through party selection
108+
/// If the current request is related to an active instance, this value is not relevant.
109+
/// The selected party ID is always whatever the user has selected in the party selection screen.
110+
/// Party selection is used for instantiating new instances. The selected party ID becomes the instance owner party ID
111+
/// when instantiating.
103112
/// </summary>
104113
public int SelectedPartyId { get; }
105114

@@ -118,6 +127,11 @@ public sealed class User : Authenticated
118127
/// </summary>
119128
public bool InAltinnPortal { get; }
120129

130+
/// <summary>
131+
/// True if the user is self-identified/self-registered.
132+
/// </summary>
133+
public bool IsSelfIdentified => AuthenticationLevel == 0;
134+
121135
private Details? _extra;
122136
private readonly Func<int, Task<UserProfile?>> _getUserProfile;
123137
private readonly Func<int, Task<Party?>> _lookupParty;
@@ -127,6 +141,7 @@ public sealed class User : Authenticated
127141

128142
internal User(
129143
int userId,
144+
string? username,
130145
int userPartyId,
131146
int authenticationLevel,
132147
string authenticationMethod,
@@ -136,6 +151,7 @@ ref ParseContext context
136151
: base(ref context)
137152
{
138153
UserId = userId;
154+
Username = username;
139155
UserPartyId = userPartyId;
140156
SelectedPartyId = selectedPartyId;
141157
AuthenticationLevel = authenticationLevel;
@@ -307,90 +323,6 @@ await _getUserProfile(UserId)
307323
}
308324
}
309325

310-
/// <summary>
311-
/// The logged in client is a user (e.g. Altinn portal/ID-porten) with auth level 0.
312-
/// This means that the user has authenticated with a username/password, which can happen using
313-
/// * Altinn "self registered users"
314-
/// * ID-porten through Ansattporten ("low"), MinID self registered eID
315-
/// These have limited access to Altinn and can only represent themselves.
316-
/// </summary>
317-
public sealed class SelfIdentifiedUser : Authenticated
318-
{
319-
/// <summary>
320-
/// Username
321-
/// </summary>
322-
public string Username { get; }
323-
324-
/// <summary>
325-
/// User ID
326-
/// </summary>
327-
public int UserId { get; }
328-
329-
/// <summary>
330-
/// Party ID
331-
/// </summary>
332-
public int PartyId { get; }
333-
334-
/// <summary>
335-
/// Method of authentication, e.g. "idporten" or "maskinporten"
336-
/// </summary>
337-
public string AuthenticationMethod { get; }
338-
339-
private Details? _extra;
340-
private readonly Func<int, Task<UserProfile?>> _getUserProfile;
341-
private readonly ApplicationMetadata _appMetadata;
342-
343-
internal SelfIdentifiedUser(
344-
string username,
345-
int userId,
346-
int partyId,
347-
string authenticationMethod,
348-
ref ParseContext context
349-
)
350-
: base(ref context)
351-
{
352-
Username = username;
353-
UserId = userId;
354-
PartyId = partyId;
355-
AuthenticationMethod = authenticationMethod;
356-
// Since they are self-identified, they are always 0
357-
AuthenticationLevel = 0;
358-
_getUserProfile = context.GetUserProfile;
359-
_appMetadata = context.AppMetadata;
360-
}
361-
362-
/// <summary>
363-
/// Authentication level
364-
/// </summary>
365-
public int AuthenticationLevel { get; }
366-
367-
/// <summary>
368-
/// Detailed information about a logged in user
369-
/// </summary>
370-
public sealed record Details(Party Party, UserProfile Profile, bool RepresentsSelf, bool CanInstantiate);
371-
372-
/// <summary>
373-
/// Load the details for the current user.
374-
/// </summary>
375-
/// <returns></returns>
376-
public async Task<Details> LoadDetails()
377-
{
378-
if (_extra is not null)
379-
return _extra;
380-
381-
var userProfile =
382-
await _getUserProfile(UserId)
383-
?? throw new AuthenticationContextException(
384-
$"Could not get user profile for logged in self identified user: {UserId}"
385-
);
386-
387-
var party = userProfile.Party;
388-
var canInstantiate = InstantiationHelper.IsPartyAllowedToInstantiate(party, _appMetadata.PartyTypesAllowed);
389-
_extra = new Details(party, userProfile, RepresentsSelf: true, canInstantiate);
390-
return _extra;
391-
}
392-
}
393-
394326
/// <summary>
395327
/// The logged in client is an organisation (but they have not authenticated as an Altinn service owner).
396328
/// Authentication has been done through Maskinporten.
@@ -690,13 +622,6 @@ internal static Authenticated FromLocalTest(
690622
throw new AuthenticationContextException("Missing party ID for user token");
691623

692624
ParseAuthLevel(context.AuthLevelClaim, out authLevel);
693-
if (authLevel == 0)
694-
{
695-
if (!context.UsernameClaim.IsValidString(out var usernameClaimValue))
696-
throw new AuthenticationContextException("Missing username claim for self-identified user token");
697-
698-
return new SelfIdentifiedUser(usernameClaimValue, userId, partyId.Value, "localtest", ref context);
699-
}
700625

701626
int selectedPartyId = partyId.Value;
702627
if (getSelectedParty() is { } selectedPartyStr)
@@ -706,8 +631,17 @@ internal static Authenticated FromLocalTest(
706631

707632
selectedPartyId = selectedParty;
708633
}
709-
710-
return new User(userId, partyId.Value, authLevel, "localtest", selectedPartyId, ref context);
634+
context.UsernameClaim.IsValidString(out var usernameClaimValue);
635+
636+
return new User(
637+
userId,
638+
usernameClaimValue,
639+
partyId.Value,
640+
authLevel,
641+
"localtest",
642+
selectedPartyId,
643+
ref context
644+
);
711645
}
712646

713647
internal record struct ParseContext(
@@ -936,7 +870,7 @@ internal static Authenticated From(
936870
return NewUser(ref context);
937871
}
938872

939-
static Authenticated NewUser(ref ParseContext context)
873+
static Authenticated.User NewUser(ref ParseContext context)
940874
{
941875
if (!context.UserIdClaim.Exists)
942876
throw new AuthenticationContextException("Missing user ID claim for user token");
@@ -959,19 +893,6 @@ static Authenticated NewUser(ref ParseContext context)
959893
throw new AuthenticationContextException("Missing or invalid authentication method claim for user token");
960894

961895
ParseAuthLevel(context.AuthLevelClaim, out var authLevel);
962-
if (authLevel == 0)
963-
{
964-
if (!context.UsernameClaim.IsValidString(out var usernameClaimValue))
965-
throw new AuthenticationContextException("Missing username claim for self-identified user token");
966-
967-
return new SelfIdentifiedUser(
968-
usernameClaimValue,
969-
userId.Value,
970-
partyId.Value,
971-
authMethodClaimValue,
972-
ref context
973-
);
974-
}
975896

976897
int selectedPartyId = partyId.Value;
977898
if (context.GetSelectedParty() is { } selectedPartyStr)
@@ -982,7 +903,17 @@ ref context
982903
selectedPartyId = selectedParty;
983904
}
984905

985-
return new User(userId.Value, partyId.Value, authLevel, authMethodClaimValue, selectedPartyId, ref context);
906+
context.UsernameClaim.IsValidString(out var usernameClaimValue);
907+
908+
return new User(
909+
userId.Value,
910+
usernameClaimValue,
911+
partyId.Value,
912+
authLevel,
913+
authMethodClaimValue,
914+
selectedPartyId,
915+
ref context
916+
);
986917
}
987918

988919
static Org NewOrg(ref ParseContext context)

src/Altinn.App.Core/Features/Telemetry/TelemetryActivityExtensions.cs

-8
Original file line numberDiff line numberDiff line change
@@ -373,14 +373,6 @@ internal static Activity SetProblemDetails(this Activity activity, ProblemDetail
373373
activity.SetTag(Labels.UserAuthenticationInAltinnPortal, auth.InAltinnPortal);
374374
break;
375375
}
376-
case Authenticated.SelfIdentifiedUser auth:
377-
{
378-
activity.SetUserId(auth.UserId);
379-
activity.SetUserPartyId(auth.PartyId);
380-
activity.SetAuthenticationMethod(auth.AuthenticationMethod);
381-
activity.SetAuthenticationLevel(auth.AuthenticationLevel);
382-
break;
383-
}
384376
case Authenticated.Org auth:
385377
{
386378
activity.SetOrganisationNumber(auth.OrgNo);

0 commit comments

Comments
 (0)