37
37
import com .nimbusds .openid .connect .sdk .claims .AccessTokenHash ;
38
38
import com .nimbusds .openid .connect .sdk .validators .IDTokenValidator ;
39
39
import com .nimbusds .openid .connect .sdk .validators .InvalidHashException ;
40
+ import net .minidev .json .JSONArray ;
41
+ import net .minidev .json .JSONObject ;
40
42
import org .elasticsearch .ElasticsearchSecurityException ;
41
43
import org .elasticsearch .action .ActionListener ;
42
44
import org .elasticsearch .action .support .PlainActionFuture ;
72
74
import java .util .UUID ;
73
75
74
76
import static java .time .Instant .now ;
77
+ import static org .hamcrest .Matchers .containsInAnyOrder ;
75
78
import static org .hamcrest .Matchers .containsString ;
76
79
import static org .hamcrest .Matchers .equalTo ;
77
80
import static org .hamcrest .Matchers .instanceOf ;
@@ -96,7 +99,9 @@ public void setup() {
96
99
97
100
@ After
98
101
public void cleanup () {
99
- authenticator .close ();
102
+ if (authenticator != null ) {
103
+ authenticator .close ();
104
+ }
100
105
}
101
106
102
107
private OpenIdConnectAuthenticator buildAuthenticator () throws URISyntaxException {
@@ -632,6 +637,140 @@ public void testImplicitFlowFailsWithUnsignedJwt() throws Exception {
632
637
assertThat (e .getCause ().getMessage (), containsString ("Signed ID token expected" ));
633
638
}
634
639
640
+ public void testJsonObjectMerging () throws Exception {
641
+ final Nonce nonce = new Nonce ();
642
+ final String subject = "janedoe" ;
643
+ final Tuple <Key , JWKSet > keyMaterial = getRandomJwkForType (randomFrom ("ES" , "RS" ));
644
+ final JWK jwk = keyMaterial .v2 ().getKeys ().get (0 );
645
+ RelyingPartyConfiguration rpConfig = getRpConfig (jwk .getAlgorithm ().getName ());
646
+ OpenIdConnectProviderConfiguration opConfig = getOpConfig ();
647
+ JSONObject address = new JWTClaimsSet .Builder ()
648
+ .claim ("street_name" , "12, Test St." )
649
+ .claim ("locality" , "New York" )
650
+ .claim ("region" , "NY" )
651
+ .claim ("country" , "USA" )
652
+ .build ()
653
+ .toJSONObject ();
654
+ JSONObject idTokenObject = new JWTClaimsSet .Builder ()
655
+ .jwtID (randomAlphaOfLength (8 ))
656
+ .audience (rpConfig .getClientId ().getValue ())
657
+ .expirationTime (Date .from (now ().plusSeconds (3600 )))
658
+ .issuer (opConfig .getIssuer ().getValue ())
659
+ .issueTime (Date .from (now ().minusSeconds (200 )))
660
+ .notBeforeTime (Date .from (now ().minusSeconds (200 )))
661
+ .claim ("nonce" , nonce )
662
+ .claim ("given_name" , "Jane Doe" )
663
+ .claim ("family_name" , "Doe" )
664
+ .claim ("profile" , "https://test-profiles.com/jane.doe" )
665
+ .claim ("name" , "Jane" )
666
+ .
claim (
"email" ,
"[email protected] " )
667
+ .claim ("roles" , new JSONArray ().appendElement ("role1" ).appendElement ("role2" ).appendElement ("role3" ))
668
+ .claim ("address" , address )
669
+ .subject (subject )
670
+ .build ()
671
+ .toJSONObject ();
672
+
673
+ JSONObject userinfoObject = new JWTClaimsSet .Builder ()
674
+ .claim ("given_name" , "Jane Doe" )
675
+ .claim ("family_name" , "Doe" )
676
+ .claim ("profile" , "https://test-profiles.com/jane.doe" )
677
+ .claim ("name" , "Jane" )
678
+ .
claim (
"email" ,
"[email protected] " )
679
+ .subject (subject )
680
+ .build ()
681
+ .toJSONObject ();
682
+
683
+ OpenIdConnectAuthenticator .mergeObjects (idTokenObject , userinfoObject );
684
+ assertTrue (idTokenObject .containsKey ("given_name" ));
685
+ assertTrue (idTokenObject .containsKey ("family_name" ));
686
+ assertTrue (idTokenObject .containsKey ("profile" ));
687
+ assertTrue (idTokenObject .containsKey ("name" ));
688
+ assertTrue (idTokenObject .containsKey ("email" ));
689
+ assertTrue (idTokenObject .containsKey ("address" ));
690
+ assertTrue (idTokenObject .containsKey ("roles" ));
691
+ assertTrue (idTokenObject .containsKey ("nonce" ));
692
+ assertTrue (idTokenObject .containsKey ("sub" ));
693
+ assertTrue (idTokenObject .containsKey ("jti" ));
694
+ assertTrue (idTokenObject .containsKey ("aud" ));
695
+ assertTrue (idTokenObject .containsKey ("exp" ));
696
+ assertTrue (idTokenObject .containsKey ("iss" ));
697
+ assertTrue (idTokenObject .containsKey ("iat" ));
698
+ assertTrue (idTokenObject .containsKey ("email" ));
699
+
700
+ // Claims with different types throw an error
701
+ JSONObject wrongTypeInfo = new JWTClaimsSet .Builder ()
702
+ .claim ("given_name" , "Jane Doe" )
703
+ .claim ("family_name" , 123334434 )
704
+ .claim ("profile" , "https://test-profiles.com/jane.doe" )
705
+ .claim ("name" , "Jane" )
706
+ .
claim (
"email" ,
"[email protected] " )
707
+ .subject (subject )
708
+ .build ()
709
+ .toJSONObject ();
710
+
711
+ final IllegalStateException e = expectThrows (IllegalStateException .class , () -> {
712
+ OpenIdConnectAuthenticator .mergeObjects (idTokenObject , wrongTypeInfo );
713
+ });
714
+
715
+ // Userinfo Claims overwrite ID Token claims
716
+ JSONObject overwriteUserInfo = new JWTClaimsSet .Builder ()
717
+ .claim ("given_name" , "Jane Doe" )
718
+ .claim ("family_name" , "Doe" )
719
+ .claim ("profile" , "https://test-profiles.com/jane.doe2" )
720
+ .claim ("name" , "Jane" )
721
+ .
claim (
"email" ,
"[email protected] " )
722
+ .subject (subject )
723
+ .build ()
724
+ .toJSONObject ();
725
+
726
+ OpenIdConnectAuthenticator .mergeObjects (idTokenObject , overwriteUserInfo );
727
+ assertThat (
idTokenObject .
getAsString (
"email" ),
equalTo (
"[email protected] " ));
728
+ assertThat (idTokenObject .getAsString ("profile" ), equalTo ("https://test-profiles.com/jane.doe" ));
729
+
730
+ // Merging Arrays
731
+ JSONObject userInfoWithRoles = new JWTClaimsSet .Builder ()
732
+ .claim ("given_name" , "Jane Doe" )
733
+ .claim ("family_name" , "Doe" )
734
+ .claim ("profile" , "https://test-profiles.com/jane.doe" )
735
+ .claim ("name" , "Jane" )
736
+ .
claim (
"email" ,
"[email protected] " )
737
+ .claim ("roles" , new JSONArray ().appendElement ("role4" ).appendElement ("role5" ))
738
+ .subject (subject )
739
+ .build ()
740
+ .toJSONObject ();
741
+
742
+ OpenIdConnectAuthenticator .mergeObjects (idTokenObject , userInfoWithRoles );
743
+ assertThat ((JSONArray ) idTokenObject .get ("roles" ), containsInAnyOrder ("role1" , "role2" , "role3" , "role4" , "role5" ));
744
+
745
+ // Merging nested objects
746
+ JSONObject addressUserInfo = new JWTClaimsSet .Builder ()
747
+ .claim ("street_name" , "12, Test St." )
748
+ .claim ("locality" , "New York" )
749
+ .claim ("postal_code" , "10024" )
750
+ .build ()
751
+ .toJSONObject ();
752
+ JSONObject userInfoWithAddress = new JWTClaimsSet .Builder ()
753
+ .claim ("given_name" , "Jane Doe" )
754
+ .claim ("family_name" , "Doe" )
755
+ .claim ("profile" , "https://test-profiles.com/jane.doe" )
756
+ .claim ("name" , "Jane" )
757
+ .
claim (
"email" ,
"[email protected] " )
758
+ .claim ("roles" , new JSONArray ().appendElement ("role4" ).appendElement ("role5" ))
759
+ .claim ("address" , addressUserInfo )
760
+ .subject (subject )
761
+ .build ()
762
+ .toJSONObject ();
763
+ OpenIdConnectAuthenticator .mergeObjects (idTokenObject , userInfoWithAddress );
764
+ assertTrue (idTokenObject .containsKey ("address" ));
765
+ JSONObject combinedAddress = (JSONObject ) idTokenObject .get ("address" );
766
+ assertTrue (combinedAddress .containsKey ("street_name" ));
767
+ assertTrue (combinedAddress .containsKey ("locality" ));
768
+ assertTrue (combinedAddress .containsKey ("street_name" ));
769
+ assertTrue (combinedAddress .containsKey ("postal_code" ));
770
+ assertTrue (combinedAddress .containsKey ("region" ));
771
+ assertTrue (combinedAddress .containsKey ("country" ));
772
+ }
773
+
635
774
private OpenIdConnectProviderConfiguration getOpConfig () throws URISyntaxException {
636
775
return new OpenIdConnectProviderConfiguration (
637
776
new Issuer ("https://op.example.com" ),
0 commit comments