@@ -209,10 +209,6 @@ pub(crate) enum FormData {
209209 accept_terms : Option < String > ,
210210 } ,
211211 Link ,
212- Associate {
213- #[ serde( default ) ]
214- username : Option < String > ,
215- } ,
216212}
217213
218214impl ToFormState for FormData {
@@ -653,10 +649,46 @@ pub(crate) async fn post(
653649 session
654650 }
655651
656- ( None , None , FormData :: Associate { username } ) => {
657- //user already exists, but it is not linked, neither connected
658- //proceed by associating the link and connect the user
652+ ( None , None , FormData :: Link ) => {
653+ // User already exists, but it is not linked, neither logged in
654+ // Proceed by associating the link to the user and log in the user
655+ // Upstream_session is used to re-render the username as it is the only source of truth
656+
657+ let id_token = upstream_session. id_token ( ) . map ( Jwt :: try_from) . transpose ( ) ?;
659658
659+ let provider = repo
660+ . upstream_oauth_provider ( )
661+ . lookup ( link. provider_id )
662+ . await ?
663+ . ok_or ( RouteError :: ProviderNotFound ( link. provider_id ) ) ?;
664+
665+ // Let's import the username from the localpart claim
666+ let env = environment ( ) ;
667+
668+ let mut context = AttributeMappingContext :: new ( ) ;
669+ if let Some ( id_token) = id_token {
670+ let ( _, payload) = id_token. into_parts ( ) ;
671+ context = context. with_id_token_claims ( payload) ;
672+ }
673+ if let Some ( extra_callback_parameters) = upstream_session. extra_callback_parameters ( ) {
674+ context = context. with_extra_callback_parameters ( extra_callback_parameters. clone ( ) ) ;
675+ }
676+ if let Some ( userinfo) = upstream_session. userinfo ( ) {
677+ context = context. with_userinfo_claims ( userinfo. clone ( ) ) ;
678+ }
679+ let context = context. build ( ) ;
680+
681+
682+ //Claims import must be `require` or `force` at this stage
683+ let template = provider
684+ . claims_imports
685+ . localpart
686+ . template
687+ . as_deref ( )
688+ . unwrap_or ( DEFAULT_LOCALPART_TEMPLATE ) ;
689+
690+ let username = render_attribute_template ( & env, template, & context, true ) ?;
691+
660692 let maybe_user = repo. user ( ) . find_by_username ( & username. unwrap ( ) ) . await ?;
661693
662694 if maybe_user. is_some ( ) {
@@ -706,6 +738,7 @@ pub(crate) async fn post(
706738 let env = environment ( ) ;
707739
708740 let mut context = AttributeMappingContext :: new ( ) ;
741+
709742 if let Some ( id_token) = id_token {
710743 let ( _, payload) = id_token. into_parts ( ) ;
711744 context = context. with_id_token_claims ( payload) ;
@@ -1250,8 +1283,7 @@ mod tests {
12501283 let request = Request :: post ( & * mas_router:: UpstreamOAuth2Link :: new ( link. id ) . path ( ) ) . form (
12511284 serde_json:: json!( {
12521285 "csrf" : csrf_token,
1253- "action" : "associate" ,
1254- "username" : user. username. clone( )
1286+ "action" : "link"
12551287 } ) ,
12561288 ) ;
12571289 let request = cookies. with_cookies ( request) ;
0 commit comments