@@ -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 )
0 commit comments