@@ -110,6 +110,20 @@ impl ConfigurationSection for UpstreamOAuth2Config {
110110                    } 
111111                } 
112112            } 
113+ 
114+             if  !provider. claims_imports . localpart . on_conflict . is_default ( ) 
115+                 && !matches ! ( 
116+                     provider. claims_imports. localpart. action, 
117+                     ImportAction :: Force  | ImportAction :: Require 
118+                 ) 
119+             { 
120+                 return  annotate ( figment:: Error :: custom ( 
121+                     "The field `action` must be either `force` or `require` when `on_conflict` is set to `add`" , 
122+                 ) ) ; 
123+             } 
124+ 
125+             //TODO : check that claims imports use on_conflict where it is not 
126+             // supported? 
113127        } 
114128
115129        Ok ( ( ) ) 
@@ -183,6 +197,26 @@ impl ImportAction {
183197    } 
184198} 
185199
200+ /// How to handle an existing localpart claim 
201+ #[ derive( Debug ,  Clone ,  Copy ,  PartialEq ,  Eq ,  Serialize ,  Deserialize ,  Default ,  JsonSchema ) ]  
202+ #[ serde( rename_all = "lowercase" ) ]  
203+ pub  enum  OnConflict  { 
204+     /// Fails the sso login on conflict 
205+      #[ default]  
206+     Fail , 
207+ 
208+     /// Adds the oauth identity link, regardless of whether there is an existing 
209+      /// link or not 
210+      Add , 
211+ } 
212+ 
213+ impl  OnConflict  { 
214+     #[ allow( clippy:: trivially_copy_pass_by_ref) ]  
215+     const  fn  is_default ( & self )  -> bool  { 
216+         matches ! ( self ,  OnConflict :: Fail ) 
217+     } 
218+ } 
219+ 
186220/// What should be done for the subject attribute 
187221#[ derive( Debug ,  Clone ,  PartialEq ,  Eq ,  Serialize ,  Deserialize ,  Default ,  JsonSchema ) ]  
188222pub  struct  SubjectImportPreference  { 
@@ -211,6 +245,10 @@ pub struct LocalpartImportPreference {
211245     /// If not provided, the default template is `{{ user.preferred_username }}` 
212246     #[ serde( default ,  skip_serializing_if = "Option::is_none" ) ]  
213247    pub  template :  Option < String > , 
248+ 
249+     /// How to handle conflicts on the claim, default value is `Fail` 
250+      #[ serde( default ,  skip_serializing_if = "OnConflict::is_default" ) ]  
251+     pub  on_conflict :  OnConflict , 
214252} 
215253
216254impl  LocalpartImportPreference  { 
0 commit comments