Compare commits

...
264 Commits
Author SHA1 Message Date
Marek Posolda 3e71aeddf3 Merge pull request #3479 from hmlnarik/KEYCLOAK-3469-UserRealmRoleMapper
KEYCLOAK-3469 Make role mappers account for user groups
2016-11-18 09:21:56 +01:00
Marek Posolda a2e00e4c3b Merge pull request #3497 from vramik/KEYCLOAK-3899
KEYCLOAK-3899 Make migration properties available in tests
2016-11-18 09:12:10 +01:00
Marek Posolda 2c6e9be8e5 Merge pull request #3504 from vramik/KEYCLOAK-3907
KEYCLOAK-3907 Test backwards compatibility of realm import
2016-11-18 09:10:59 +01:00
Marek Posolda fce41c0ab8 Merge pull request #3507 from mhajas/KEYCLOAK-3916
KEYCLOAK-3916 Remove classes with missing parent
2016-11-18 09:02:10 +01:00
Marek Posolda ca5c806f58 Merge pull request #3513 from pedroigor/KEYCLOAK-3830
[KEYCLOAK-3830] - Properly handle public resources when using security-constraints
2016-11-18 08:59:21 +01:00
Marek Posolda 1e8f5f1a51 Merge pull request #3514 from pedroigor/KEYCLOAK-3674
[KEYCLOAK-3674] - Review policies dropbox options
2016-11-18 08:56:56 +01:00
Marek Posolda b434c2b9cf Merge pull request #3510 from ssilvert/delete-subflows
KEYCLOAK-3681: Delete top flow doesn't remove all subflows
2016-11-18 08:50:13 +01:00
Marek Posolda 60afd280c3 Merge pull request #3512 from abstractj/KEYCLOAK-3918
[KEYCLOAK-3918] - Server won't boot on Windows
2016-11-18 08:44:37 +01:00
Pedro Igor 9b2ef96b22 [KEYCLOAK-3830] - Allow to configure enforcement-mode to a path definition 2016-11-17 20:50:28 -02:00
Pedro Igor 44ee53b0d8 [KEYCLOAK-3830] - Only enforce permissions when there is a KeycloakSecurityContext. 2016-11-17 20:50:17 -02:00
Pedro Igor Craveiro e Silva cc9131441e [KEYCLOAK-3674] - Review policies dropbox options 2016-11-17 20:43:32 -02:00
Marek Posolda 5e496fb9bb Merge pull request #3511 from mposolda/ispn-invalidations-rebase
KEYCLOAK-3857 Clustered invalidation cache fixes and refactoring. Sup…
2016-11-16 23:10:48 +01:00
Bruno Oliveira 5c089e45d4 [KEYCLOAK-3918] - Server won't boot on Windows 2016-11-16 19:37:48 -02:00
mposolda a27be0cee7 KEYCLOAK-3857 Clustered invalidation cache fixes and refactoring. Support for cross-DC for invalidation caches. 2016-11-16 22:29:23 +01:00
Stan Silvert a0ae8c126e Add comment to test 2016-11-16 12:45:34 -05:00
Stan Silvert 55556fc63c KEYCLOAK-3681: Delete top flow doesn't remove all subflows 2016-11-16 12:43:11 -05:00
mhajas 475c6403cc KEYCLOAK-3916 Remove classes with missing parent 2016-11-16 15:27:35 +01:00
Stian Thorgersen cf17687b8b Merge pull request #3506 from abstractj/KEYCLOAK-3913
[KEYCLOAK-3913] - Native libraries included within SSSD jar
2016-11-16 14:56:53 +01:00
Vlasta Ramik 50339f6f0e Test backwards compatibility of realm import 2016-11-16 13:17:04 +01:00
Stian Thorgersen 26b1541f4a Merge pull request #3476 from abstractj/KEYCLOAK-3875
[KEYCLOAK-3875] - Conditional OTP Forms not working as expected
2016-11-16 12:44:50 +01:00
Stian Thorgersen 1c3a475d1e Merge pull request #3485 from hmlnarik/KEYCLOAK-3071
KEYCLOAK-3071 Add SOAP and PAOS endpoints to valid redirect URIs on SP import
2016-11-16 12:38:45 +01:00
Stian Thorgersen 65136fabdd Merge pull request #3486 from hmlnarik/KEYCLOAK-3488
KEYCLOAK-3488 Fix typo in SamlPrincipal
2016-11-16 12:21:50 +01:00
Stian Thorgersen 70d1ac7162 Merge pull request #3505 from vramik/KEYCLOAK-3910
KEYCLOAK-3910 review clean-start tests
2016-11-16 12:21:21 +01:00
Stian Thorgersen b1f35ff974 Merge pull request #3491 from hmlnarik/KEYCLOAK-3087-XmlEncryptionUtil
KEYCLOAK-3087 XmlEncryptionUtil cleanup, 3DES removal
2016-11-16 12:17:26 +01:00
Stian Thorgersen f5d4554b39 Merge pull request #3494 from stianst/KEYCLOAK-3882
KEYCLOAK-3882 Move more provider factories and SPIs to private
2016-11-16 12:16:18 +01:00
Bruno Oliveira 8a0cb507c5 [KEYCLOAK-3913] - Native libraries included within SSSD jar
- Revert "[KEYCLOAK-3580] - Migrate DBus Java from Unix Socket C library to jnr-unixsocket"
    This reverts commit 6c5d1b9214.
  - Use JNA RPM, instead of Maven
2016-11-16 09:14:05 -02:00
Stian Thorgersen 89a43b8771 Merge pull request #3466 from melahn/update-maven-version
updated requireMavenVersion in parent pom to 3.2.1
2016-11-16 12:13:48 +01:00
Stian Thorgersen 83571dba5d Merge pull request #3495 from rigon/patch-2
Update README.md
2016-11-16 12:13:00 +01:00
Pedro Igor a6d59faf98 Merge pull request #3503 from pedroigor/KEYCLOAK-3339
[KEYCLOAK-3339] - Enable authorization services to EAP6 adapter
2016-11-16 08:38:44 -02:00
Stan Silvert 9512180406 Merge pull request #3502 from ssilvert/hide-role-selector
KEYCLOAK-3905: Role selector sometimes displayed when client full scope
2016-11-15 10:24:01 -05:00
Vlasta Ramik 0f0f20716f Review clean-start tests 2016-11-15 14:29:13 +01:00
Stian Thorgersen b4f072ed81 KEYCLOAK-3882 Move more provider factories and SPIs to private 2016-11-15 12:05:25 +01:00
Pedro Igor 394a9daa64 [KEYCLOAK-3906] - Update IP-BOM 6.0.10.Final 2016-11-15 01:03:35 +00:00
Pedro Igor a3beef754c [KEYCLOAK-3339] - Enable authorization services to EAP6 adapter 2016-11-15 00:26:29 +00:00
Bill Burke 94afba91a0 Merge pull request #3501 from patriot1burke/master
LDAP port to UserStorageSPI
2016-11-14 17:24:39 -05:00
Bill Burke 8794416241 fix db2 2016-11-14 16:22:30 -05:00
Bill Burke f471ad46c9 fix server-private spi changes 2016-11-14 15:28:08 -05:00
Marek Posolda 989a701e95 Merge pull request #3498 from hmlnarik/KEYCLOAK-3734
KEYCLOAK-3734 Unify master changelog of DB2 and other databases
2016-11-14 21:18:27 +01:00
Marek Posolda 37c1c84e04 Merge pull request #3499 from abstractj/KEYCLOAK-3900
[KEYCLOAK-3900] - SSSD Provider: NullPointerException when SSSD is stopped
2016-11-14 21:16:19 +01:00
Bill Burke 39ffd3d756 fix pom 2016-11-14 15:15:20 -05:00
Stan Silvert b920c7b2c4 KEYCLOAK-3905: Role selector sometimes displayed when client full scope
enabled
2016-11-14 15:11:22 -05:00
Pedro Igor a2c54b03c8 Merge pull request #3500 from pedroigor/KEYCLOAK-3554-new
[KEYCLOAK-3554] - Properly handle dependencies between policies when importing settings
2016-11-14 18:10:37 -02:00
Bill Burke 7666387277 rename directory 2016-11-14 15:10:35 -05:00
Bill Burke cc0eb47814 merge 2016-11-14 15:09:41 -05:00
Bill Burke c280634bfa fix tests 2016-11-14 15:06:17 -05:00
Pedro Igor fb1cd9d27d [KEYCLOAK-3554] - Properly handle dependencies between policies when importing settings 2016-11-14 18:55:53 +00:00
Bruno Oliveira b612415a88 [KEYCLOAK-3900] - SSSD Provider: NullPointerException when SSSD is stopped 2016-11-14 16:04:18 -02:00
Hynek Mlnarik 223041bc6b KEYCLOAK-3734 Unify master changelog of DB2 and other databases 2016-11-14 15:19:54 +01:00
Vlasta Ramik ab0514041e Make migration properties available in tests 2016-11-14 13:09:03 +01:00
Hynek Mlnarik 750e942267 KEYCLOAK-3469 Make role mappers account for user groups 2016-11-14 11:38:00 +01:00
Hynek Mlnarik 17c13043d0 KEYCLOAK-3087 XmlEncryptionUtil cleanup, 3DES removal 2016-11-14 10:26:39 +01:00
Gregory Melahn 750075d0dd Will update the README.md file instead
This reverts commit b58bfe56d6.
2016-11-13 12:40:45 -05:00
Gregory Melahn 9df43e3bd2 Merge branch 'update-maven-version' of https://github.com/melahn/keycloak into update-maven-version 2016-11-13 12:25:30 -05:00
Gregory Melahn d1eaace4cf fixed maven prereq version to match pom 2016-11-13 12:24:01 -05:00
Bruno Oliveira 39f40bc005 [KEYCLOAK-3875] - Conditional OTP Forms not working as expected 2016-11-11 15:16:08 -02:00
Stian Thorgersen 6c64494620 Merge pull request #3493 from stianst/master
Try to fix Travis
2016-11-11 17:00:25 +01:00
Stian Thorgersen c9e3fe9a92 Try to fix Travis 2016-11-11 17:00:11 +01:00
Bill Burke 4ce055cede mongo ldap migration script 2016-11-11 09:06:25 -05:00
Ricardo Gonçalves 1e65174867 Update README.md 2016-11-11 12:30:42 +00:00
Pavel Drozd 1052c71124 Merge pull request #3488 from vramik/KEYCLOAK-3885
KEYCLOAK-3885 Add missing migration test for 2.3.0
2016-11-11 09:46:03 +01:00
Stian Thorgersen a86b5988b5 Merge pull request #3484 from hmlnarik/KEYCLOAK-3658
KEYCLOAK-3658 Fixed typo in condition
2016-11-11 09:41:48 +01:00
Stian Thorgersen 088f0ea630 Merge pull request #3490 from stianst/KEYCLOAK-3086
[KEYCLOAK-3086] -  NPE when accessing Account with invalid clientId s…
2016-11-11 09:35:45 +01:00
Stian Thorgersen 08dbdeb57f Merge pull request #3489 from stianst/KEYCLOAK-3882
KEYCLOAK-3882 Split server-spi into server-spi and server-spi-private
2016-11-11 09:35:08 +01:00
Bill Burke 8a5f817030 ldap jpa migration 2016-11-10 16:52:18 -05:00
Bruno Oliveira 675faee593 [KEYCLOAK-3086] - NPE when accessing Account with invalid clientId set as ?referrer, and additional referrer_uri set 2016-11-10 13:49:40 +01:00
Stian Thorgersen 7e33f4a7d1 KEYCLOAK-3882 Split server-spi into server-spi and server-spi-private 2016-11-10 13:28:42 +01:00
Vlasta Ramik 71c88a8dfc Add missing migration test for 2.3.0 2016-11-10 11:02:26 +01:00
Stian Thorgersen 52a4509ada Merge pull request #3483 from hmlnarik/KEYCLOAK-3870-keycloak-saml-xsd
KEYCLOAK-3870 Schema for keycloak-saml.xml
2016-11-10 08:20:24 +01:00
Stian Thorgersen 1ee6df412e Merge pull request #3482 from vramik/KEYCLOAK-2741
KEYCLOAK-2741 remove KEYCLOAK_REMEMBERME when user logs in without rememberme checked
2016-11-10 07:45:07 +01:00
Bill Burke 94076a3b24 admin console ui 2016-11-09 17:34:07 -05:00
Hynek Mlnarik 43002f7a8a KEYCLOAK-3488 Fix typo 2016-11-09 15:11:45 +01:00
Hynek Mlnarik 8816b55843 KEYCLOAK-3071 Add SOAP and PAOS endpoints to valid redirect URIs on SP import 2016-11-09 14:13:53 +01:00
Hynek Mlnarik 9c724b616d KEYCLOAK-3658 Fixed typo in condition 2016-11-09 11:27:33 +01:00
Hynek Mlnarik 025cf5ebaf KEYCLOAK-3870 Schema for keycloak-saml.xml
Updated schema schema for keycloak-saml.xml (added documentation, set
up enumeration instead of free string where applicable per documentation)
and updated existing keycloak-saml.xml files with schema reference.
2016-11-09 10:45:43 +01:00
Vlasta Ramik 6f1b8e1fee remove KEYCLOAK_REMEMBERME when user logs in without rememberme checked + tests 2016-11-09 10:33:46 +01:00
Bill Burke 4880c0443c ldap port admin console 2016-11-08 12:30:20 -05:00
Pavel Drozd c05057748f Merge pull request #3474 from vramik/KEYCLOAK-3489
KEYCLOAK-3489 migration tests - minor fix
2016-11-08 15:38:14 +01:00
Stian Thorgersen de7006a048 Merge pull request #3473 from hmlnarik/KEYCLOAK-3215
KEYCLOAK-3215 Use RSA-OAEP for key encryption
2016-11-08 10:16:54 +01:00
Vlasta Ramik 2b6811a366 migration tests - minor fix 2016-11-08 09:48:15 +01:00
Pavel Drozd 10f9800327 Merge pull request #3469 from mhajas/KEYCLOAK-3853
KEYCLOAK-3853 Fix keyRotation adapter test
2016-11-08 08:34:11 +01:00
Stian Thorgersen 292777259e Merge pull request #3472 from hmlnarik/KEYCLOAK-1881-saml-key-rotation
Keycloak 1881 - SAML key/cert rotation for IdP
2016-11-08 07:56:25 +01:00
Hynek Mlnarik 01c42f9359 KEYCLOAK-3215 Use RSA-OAEP for key encryption 2016-11-08 07:44:59 +01:00
Stian Thorgersen ef48594d85 Merge pull request #3470 from sebastienblanc/KEYCLOAK-3548
KEYCLOAK-3548 : Send 401 when no keycloak.json for EAP6/AS7 Adapter
2016-11-08 07:37:00 +01:00
Stian Thorgersen c9a58fad15 Merge pull request #3464 from stianst/KEYCLOAK-3692
KEYCLOAK-3692
2016-11-08 07:36:39 +01:00
Stian Thorgersen 5b54375490 Merge pull request #3468 from sebastienblanc/KEYCLOAK-3514
KEYCLOAK-3514 : fix servlet logout on bearer-only client
2016-11-08 07:35:44 +01:00
Stian Thorgersen db4f3561a5 Merge pull request #3454 from ssilvert/keystore-error-messages
KEYCLOAK-3817: More detailed errors when loading keys from JKS
2016-11-08 07:33:43 +01:00
Bill Burke f138eecc27 port KerberosLdapTest 2016-11-06 09:15:49 -05:00
Bill Burke 5a86623c88 merge 2016-11-06 08:52:10 -05:00
Bill Burke 14dc0ff92f Merge remote-tracking branch 'upstream/master' 2016-11-05 20:05:01 -04:00
Bill Burke 4302b440ee ldap port 2016-11-05 20:04:53 -04:00
Bill Burke c75dcb90c2 ldap port 2016-11-04 21:25:47 -04:00
Stan Silvert f922164a88 Merge pull request #3471 from ssilvert/otp-low-res
KEYCLOAK-3816: Tweak CSS for 1280 x 720 display
2016-11-04 17:10:22 -04:00
Hynek Mlnarik 36257863db KEYCLOAK-1881 Integration tests for key rotation in SAML IdP 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 14f96fdb4b KEYCLOAK-1881 Wildfly, AS7, EAP Adapters 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 570d71c07b KEYCLOAK-1881 Update client adapter configuration
Client adapter configuration was updated to support for customization
of HttpClient used for key retrieval similarly to OIDC. Further, it is
now possible to specify several static public keys for signature
verification in saml-client.xml.
2016-11-04 21:53:43 +01:00
Hynek Mlnarik 8ae1b1740d KEYCLOAK-1881 Client installers 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 4f9e35c0a1 KEYCLOAK-1881 Support for multiple certificates in broker (hardcoded at the moment) 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 67bb9aef3d KEYCLOAK-1881 Add switch to enable/disable generation of <Extensions>
Some SP clients might be confused by using a standard SAML protocol tag
<Extensions> which is used for signed REDIRECT binding messages to
specify signing key ID. To enable the interoperability, generation of
the tag is disabled by default and can be enabled for individual
clients.
2016-11-04 21:53:43 +01:00
Hynek Mlnarik 1ae268ec6f KEYCLOAK-1881 Include key ID for REDIRECT and use it for validation
Contrary to POST binding, signature of SAML protocol message sent using
REDIRECT binding is contained in query parameters and not in the
message. This renders <dsig:KeyName> key ID hint unusable. This commit
adds <Extensions> element in SAML protocol message containing key ID so
that key ID is present in the SAML protocol message.
2016-11-04 21:53:43 +01:00
Hynek Mlnarik 10deac0b06 KEYCLOAK-1881 KeyLocator implementation for SAML descriptor 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 057cc37b60 KEYCLOAK-1881 Clone OIDC adapter HttpClient tools to SAML adapter
and
KEYCLOAK-1881 Extract httpclient configuration from AdapterConfig
2016-11-04 21:53:43 +01:00
Hynek Mlnarik 70a8255eae KEYCLOAK-1881 Basic key locator support 2016-11-04 21:53:43 +01:00
Hynek Mlnarik d5c3bde0af KEYCLOAK-1881 Make SAML descriptor endpoint return all certificates 2016-11-04 21:53:43 +01:00
Hynek Mlnarik 5d840500af KEYCLOAK-1881 Include key ID in <ds:KeyInfo> in SAML assertions and protocol message
Changes of SAML assertion creation/parsing that are required to allow
for validation of rotating realm key: signed SAML assertions and signed
SAML protocol message now contain signing key ID in XML <dsig:KeyName>
element.
2016-11-04 21:53:43 +01:00
Hynek Mlnarik 904a5c3ca5 KEYCLOAK-3864 Add support for SAML2 <Extensions> element in protocol messages 2016-11-04 21:53:43 +01:00
Stan Silvert 66698f60d4 KEYCLOAK-3816: Tweak CSS for 1280 x 720 display 2016-11-04 15:32:19 -04:00
sebastien blanc 6c18b300a4 add integration test 2016-11-04 07:39:22 +01:00
Stian Thorgersen 6baf9b89fe Merge pull request #3467 from abstractj/KEYCLOAK-3580
[KEYCLOAK-3580] - Migrate DBus Java from Unix Socket C library to jnr-unixsocket
2016-11-04 05:57:02 +01:00
mhajas fd5f7eb165 KEYCLOAK-3853 Fix keyRotation adapter test 2016-11-03 16:04:31 +01:00
sebastien blanc 76c37de1e8 KEYCLOAK-3545: Send 401 if no kc configuration in EAP6/AS7 2016-11-03 15:39:02 +01:00
Pavel Drozd c3f3c5c6a5 Merge pull request #3453 from vramik/KEYCLOAK-2957
KEYCLOAK-2957 test
2016-11-03 15:26:14 +01:00
Pavel Drozd f2b28d8215 Merge pull request #3456 from vramik/KEYCLOAK-3579
KEYCLOAK-3579 add preview profile assumption to tests
2016-11-03 15:25:17 +01:00
Pavel Drozd 672f5d879b Merge pull request #3465 from mhajas/KEYCLOAK-3854
KEYCLOAK-3854 KEYCLOAK-3579 Move EnfrocerConfigTest out from adapter tests
2016-11-03 15:23:39 +01:00
Pavel Drozd 20a6795f74 Merge pull request #3458 from tkyjovsk/KEYCLOAK-3849
KEYCLOAK-3849 Add ability to select keycloak profile in testsuite
2016-11-03 15:21:22 +01:00
Pavel Drozd c1ef4067bc Merge pull request #3459 from mhajas/KEYCLOAK-3850
KEYCLOAK-3850 Fix test-apps-dist zip file name
2016-11-03 15:18:11 +01:00
Pavel Drozd c1fb71c031 Merge pull request #3463 from mhajas/KEYCLOAK-3841
KEYCLOAK-3841 Remove missing dependency
2016-11-03 15:15:57 +01:00
Pavel Drozd 136f3bc5f9 Merge pull request #3457 from mhajas/KEYCLOAK-3728
KEYCLOAK-3728 Test for turned off script based authenticators
2016-11-03 15:15:32 +01:00
Stian Thorgersen 2052a0dff1 Fix 2016-11-03 14:37:07 +01:00
sebastien blanc ee8c986e8e add integration test 2016-11-03 14:30:42 +01:00
Gregory Melahn b58bfe56d6 updated requireMavenVersion in parent pom to 3.2.1 2016-11-03 08:26:27 -04:00
Bruno Oliveira 6c5d1b9214 [KEYCLOAK-3580] - Migrate DBus Java from Unix Socket C library to jnr-unixsocket 2016-11-03 10:25:45 -02:00
Pedro Igor 97be09a3bc Merge pull request #3462 from pedroigor/KEYCLOAK-3704
[KEYCLOAK-3704] - Owner validation and removal
2016-11-03 09:20:16 -02:00
mhajas 6605ba1362 KEYCLOAK-3854 Move EnfrocerConfigTest out from adapter tests 2016-11-03 09:43:49 +01:00
Stian Thorgersen ac18b6c71e KEYCLOAK-3692 2016-11-03 08:33:56 +01:00
mhajas d9069e0955 KEYCLOAK-3841 Remove missing dependency 2016-11-03 08:27:13 +01:00
Stan Silvert 3f98f23422 Merge pull request #3460 from ssilvert/otp-low-res
KEYCLOAK-3816: Broken OTP setup with smaller resolutions
2016-11-02 20:25:19 -04:00
Pedro Igor 706c1e2660 [KEYCLOAK-3704] - Registering UserSinchronizer to remove resources when the owner is removed 2016-11-02 21:40:58 -02:00
Pedro Igor 95d2130405 [KEYCLOAK-3704] - Checkign if owner is a valid user 2016-11-02 21:01:24 -02:00
Pedro Igor 683428a2c2 Merge pull request #3461 from pedroigor/KEYCLOAK-3555
[KEYCLOAK-3555] - Filtering photoz authz config file to update project version
2016-11-02 20:59:03 -02:00
Pedro Igor a315919dfc [KEYCLOAK-3555] - Filtering photoz authz config file to update project version. 2016-11-02 18:11:30 -02:00
Stan Silvert 1b89472451 KEYCLOAK-3817: Fix tests 2016-11-02 14:21:54 -04:00
Stan Silvert ae2a1e929f KEYCLOAK-3816: Broken OTP setup with smaller resolutions 2016-11-02 13:53:15 -04:00
mhajas ad995934b0 KEYCLOAK-3728 Test for turned off script based authenticators 2016-11-02 16:51:55 +01:00
mhajas c5b6507830 KEYCLOAK-3850 Fix test-apps-dist zip file name 2016-11-02 16:49:25 +01:00
Tomas Kyjovsky d7c5f991c8 KEYCLOAK-3579: added ability to select keycloak.profile in testsuite 2016-11-02 15:58:01 +01:00
Vlasta Ramik cef1973ee4 KEYCLOAK-3579 add preview profile assumption to tests 2016-11-02 14:22:03 +01:00
sebastien blanc d98c375495 KEYCLOAK-3514 : Don't call logout for bearer-only client 2016-11-02 11:39:37 +01:00
Pavel Drozd da516a78b3 Merge pull request #3450 from mhajas/KEYCLOAK-3841
KEYCLOAK-3841 Testing of Hawtio console on EAP6 + Fuse integration
2016-11-02 10:54:52 +01:00
Pavel Drozd a0f359c93c Merge pull request #3452 from mhajas/KEYCLOAK-3142
KEYCLOAK-3142 Check ResourceType in AdminEvent test
2016-11-02 10:27:54 +01:00
Pedro Igor 4bf5da8fac Merge pull request #3371 from brewers/bug/cache-dynamic-resource
KEYCLOAK-3752 : Include programmatically created resources in the resource cache
2016-11-02 07:19:04 -02:00
Pedro Igor 44977207e3 Merge pull request #3402 from brewers/feature/js-entitlement-request
KEYCLOAK-3777: Add client api for requesting entitlements with permission requests
2016-11-02 07:15:02 -02:00
Pavel Drozd 893963f339 Merge pull request #3449 from vramik/KEYCLOAK-3489
KEYCLOAK-3489 add profile to tests module for testing migration for productized version
2016-11-01 19:10:13 +01:00
Stan Silvert a5e5f4cf9c KEYCLOAK-3817: More detailed errors when loading keys from JKS 2016-11-01 13:54:34 -04:00
Vlasta Ramik fdb7924d3f add test for KEYCLOAK-2957 to arquillian testsuite 2016-11-01 11:31:19 +01:00
mhajas 782620655f KEYCLOAK-3142 Check ResourceType in AdminEvent test 2016-11-01 11:09:43 +01:00
mhajas 446b57b827 KEYCLOAK-3841 Testing of Hawtio console on EAP6 + fuse integration 2016-10-31 14:35:13 +01:00
Pavel Drozd 2c287af977 Merge pull request #3432 from zschwarz/tech-preview-profile
RHSSO-473 Add preview profile job to RH-SSO CI
2016-10-31 11:24:24 +01:00
Vlasta Ramik 4bd567e610 add profile to tests module for testing migration for productized version 2016-10-31 09:29:16 +01:00
Stan Silvert 35b0872ed9 Merge pull request #3447 from ssilvert/enter-doesnt-submit
KEYCLOAK-3281: Pressing Enter in Identity Provider form causes error
2016-10-28 13:22:20 -04:00
Stan Silvert 89348af59e KEYCLOAK-3281: Pressing Enter in Identity Provider form causes error 2016-10-28 12:06:53 -04:00
Bill Burke ccaac40863 Merge pull request #3437 from patriot1burke/master
disable credential type REST and admin ui
2016-10-28 11:33:16 -04:00
Stian Thorgersen 33bd7ca45f Merge pull request #3446 from mstruk/KEYCLOAK-3767
KEYCLOAK-3767 kcreg should show hint for help if required arguments are missing
2016-10-28 14:56:24 +02:00
Marko Strukelj 408850e7bd KEYCLOAK-3767 kcreg should show hint for help if required arguments are missing 2016-10-28 11:54:48 +02:00
Stian Thorgersen f4a77c3d06 Merge pull request #3444 from stianst/KEYCLOAK-3225
KEYCLOAK-3225
2016-10-28 11:51:35 +02:00
Stian Thorgersen 3ea555bae6 Merge pull request #3443 from stianst/KEYCLOAK-3606
KEYCLOAK-3606
2016-10-28 11:51:21 +02:00
Stian Thorgersen c543035f5a Merge pull request #3442 from stianst/KEYCLOAK-3726
KEYCLOAK-3726
2016-10-28 11:51:03 +02:00
Stian Thorgersen b6b567f948 Merge pull request #3441 from stianst/KEYCLOAK-3733
KEYCLOAK-3733 Set default max results for paginated endpoints
2016-10-28 10:36:24 +02:00
Stian Thorgersen 479295cfd2 KEYCLOAK-3225
Modifying user's Identity Provider Links requires manage-realm client role
2016-10-28 10:25:41 +02:00
Stian Thorgersen a78cfa4b2c Merge pull request #3440 from stianst/KEYCLOAK-3667
KEYCLOAK-3667
2016-10-28 10:13:06 +02:00
Stian Thorgersen c6caeb3bec Merge pull request #3439 from stianst/KEYCLOAK-3828
KEYCLOAK-3828
2016-10-28 10:12:51 +02:00
Stian Thorgersen 5f58c96258 KEYCLOAK-3606
keycloak.js calls localStorage.key(localStorage.length) indirectly
2016-10-28 10:05:57 +02:00
Stian Thorgersen bb1d255c40 KEYCLOAK-3726
Add supported WildFly version to server overlay
2016-10-28 09:43:51 +02:00
Stian Thorgersen a9d47287ee KEYCLOAK-3733 Set default max results for paginated endpoints 2016-10-28 09:15:05 +02:00
Stian Thorgersen 3d46b4c425 KEYCLOAK-3667 2016-10-28 08:43:24 +02:00
Stian Thorgersen db428dad1d KEYCLOAK-3828
Component uses wrong role
2016-10-28 07:56:44 +02:00
Stian Thorgersen 4cc44bc174 Merge pull request #3420 from bdalenoord/master
KEYCLOAK-3807: Calling 'setHandler' is forbidden
2016-10-28 06:45:47 +02:00
Stian Thorgersen 3e5f490882 Merge pull request #3424 from sebastienblanc/KEYCLOAK-3669
KEYCLOAK-3669: Fix Tomcat Adapter for 8.5.5
2016-10-28 06:45:01 +02:00
Stian Thorgersen 7579606ac4 Merge pull request #3431 from mstruk/KEYCLOAK-3766
KEYCLOAK-3766 kcreg should display help when no arguments are passed to command
2016-10-28 06:44:07 +02:00
Stian Thorgersen ee4712b2e9 Merge pull request #3434 from sebastienblanc/KEYCLOAK-3796
KEYCLOAK-3796 : add missing setters
2016-10-28 06:42:59 +02:00
Stian Thorgersen 2d1a458f5d Merge pull request #3408 from hmlnarik/KEYCLOAK-3793
KEYCLOAK-3793 Replace httpclient 4.4 calls with those available in 4.3
2016-10-28 06:41:48 +02:00
Stian Thorgersen e958bd254a Merge pull request #3435 from stianst/KEYCLOAK-3331
KEYCLOAK-3331 Reset password leads to 400 bad request when link is op…
2016-10-28 06:40:48 +02:00
Stian Thorgersen 0c6b47b9f2 Merge pull request #3433 from stianst/KEYCLOAK-3641
KEYCLOAK-3641 Clicking an invalid verification link due to re-send re…
2016-10-28 06:40:27 +02:00
Bill Burke 4cea1919f6 Merge remote-tracking branch 'upstream/master' 2016-10-27 16:17:12 -04:00
Bill Burke 91da6a47d7 disable cred types ui 2016-10-27 16:17:02 -04:00
Marek Posolda f13d759a61 Merge pull request #3436 from mposolda/master
KEYCLOAK-3800 Weird behavior when adding Trusted Hosts as Client Regi…
2016-10-27 21:23:54 +02:00
mposolda 21e423ad5f KEYCLOAK-3800 Weird behavior when adding Trusted Hosts as Client Registration Policy 2016-10-27 18:56:05 +02:00
Stian Thorgersen c6ac3266f0 KEYCLOAK-3641 Clicking an invalid verification link due to re-send removes the email verification key from the session 2016-10-27 16:16:52 +02:00
sebastien blanc 621d234adc renaming fields to align with json names 2016-10-27 16:16:30 +02:00
Stian Thorgersen ab72b2b141 KEYCLOAK-3331 Reset password leads to 400 bad request when link is opened in a different browser session 2016-10-27 16:04:45 +02:00
sebastien blanc e8dd05619b KEYCLOAK-3796 : add missing setters 2016-10-27 14:41:52 +02:00
zschwarz 25909b5e79 RHSSO-473 Add preview profile job to RH-SSO CI 2016-10-27 13:09:20 +02:00
Marko Strukelj 5925a99800 KEYCLOAK-3766 kcreg should display help when no arguments are passed to command 2016-10-27 11:08:36 +02:00
Bill Burke 6e773c84e8 Merge remote-tracking branch 'upstream/master' 2016-10-26 15:48:55 -04:00
Bill Burke 73e3f2a89b REST API for disable cred type 2016-10-26 15:48:45 -04:00
Bill Burke 69dddfa73a Merge pull request #3428 from patriot1burke/master
storage link on user detail
2016-10-26 14:58:33 -04:00
Stan Silvert 3b8972e027 Merge pull request #3423 from ssilvert/otp-low-res
KEYCLOAK-3816: Broken OTP setup with smaller resolutions
2016-10-26 13:58:29 -04:00
Stan Silvert 50b181e804 Merge pull request #3427 from ssilvert/highlight-menu
KEYCLOAK-3795: Hightlight not working in nav sidebar
2016-10-26 09:29:34 -04:00
Stian Thorgersen 21459d0f43 Merge pull request #3430 from stianst/KEYCLOAK-3819
KEYCLOAK-3819 Add support to change name of components
2016-10-26 11:39:27 +02:00
Stian Thorgersen fbe1fd8f98 Merge pull request #3429 from stianst/KEY-FIXES
Various fixes for key providers
2016-10-26 11:38:33 +02:00
Stian Thorgersen a8c844828d KEYCLOAK-3819 Add support to change name of components 2016-10-26 10:00:58 +02:00
Stian Thorgersen c0959fc562 KEYCLOAK-3808 Fix enable and active switches on default provider 2016-10-26 09:49:18 +02:00
Stian Thorgersen 6a86bb8ebe KEYCLOAK-3809 Add required to display name for key provider 2016-10-26 09:38:57 +02:00
Stian Thorgersen 76e2598c5c KEYCLOAK-3805 Use ng-if instead of ng-show in component-config template 2016-10-26 09:30:00 +02:00
Stian Thorgersen bf5e724f00 KEYCLOAK-3815 Prevent resubmission of form when creating key provider 2016-10-26 09:20:37 +02:00
Stian Thorgersen 112538a220 Merge pull request #3425 from mstruk/KEYCLOAK-2366
KEYCLOAK-2366 Unable to download key in Safari
2016-10-26 09:04:31 +02:00
Stian Thorgersen 23ea1f8939 Merge pull request #3411 from mstruk/KEYCLOAK-3789
KEYCLOAK-3789 KcRegTests are failing on CI
2016-10-26 08:57:13 +02:00
Stian Thorgersen 93f9def3e8 Merge pull request #3422 from stianst/KEYCLOAK-3811
KEYCLOAK-3811 User federation screen is missing dropdown with provide…
2016-10-26 08:48:21 +02:00
Bill Burke 8a7703b0ef fix link 2016-10-25 20:41:18 -04:00
Bill Burke 2578df1a82 Merge pull request #3426 from patriot1burke/master
user spi cache policy
2016-10-25 20:39:52 -04:00
Marko Strukelj 8dca101069 KEYCLOAK-3789 KcRegTests are failing on CI
- Ignore occasional extra empty lines at end of stream
2016-10-26 01:30:42 +02:00
Marko Strukelj 4ee759d9ec KEYCLOAK-3789 KcRegTests are failing on CI 2016-10-26 01:06:33 +02:00
Bill Burke 3129e392b0 storage link on user detail 2016-10-25 16:50:34 -04:00
Stan Silvert 0d0d614b99 KEYCLOAK-3795: Hightlight not working in nav sidebar 2016-10-25 16:32:26 -04:00
Bill Burke 3fec344fa3 finish cache policy 2016-10-25 16:13:48 -04:00
Bill Burke f8a78d5565 finish cache policy 2016-10-25 16:13:22 -04:00
Bill Burke 68e853b4bd Merge remote-tracking branch 'upstream/master' 2016-10-25 13:40:32 -04:00
Bill Burke 2cc4a920a0 fix 2016-10-25 13:40:24 -04:00
Bill Burke b67cb0e97a Merge remote-tracking branch 'upstream/master' 2016-10-25 11:44:22 -04:00
Marko Strukelj 1b2f6b763a KEYCLOAK-2366 Unable to download key in Safari
- Updated FileSaver.js to version 1.3.3
2016-10-25 16:38:26 +02:00
sebastien blanc 1c2f49ab4e KEYCLOAK-3669: Fix Tomcat Adapter for 8.5.5 2016-10-25 16:27:41 +02:00
Stan Silvert 3c237760b6 KEYCLOAK-3816: Broken OTP setup with smaller resolutions 2016-10-25 08:38:29 -04:00
Bas Dalenoord 859c5cbe1e KEYCLOAK-3807: Use 'setSecurityHandler';
'insertHandler' is a method introduced in Jetty 9, Jetty 8 should
however be supported so 'setSecurityHandler' does the same thing but
works for both 8.x and 9.x;
2016-10-25 13:59:07 +02:00
Stian Thorgersen 28f31ce57f KEYCLOAK-3811 User federation screen is missing dropdown with providers in RH-SSO theme 2016-10-25 12:44:02 +02:00
Stian Thorgersen 317749a7fd Merge pull request #3419 from stianst/KEYCLOAK-3781
KEYCLOAK-3781 Don't allow deleting the last key provider
2016-10-25 12:31:00 +02:00
Stian Thorgersen 94f33473a8 Merge pull request #3409 from matejonnet/master
Fix typo in exception message.
2016-10-25 12:30:10 +02:00
Pavel Drozd 04f2b9ac01 Merge pull request #3368 from zschwarz/oidc-filter
KEYCLOAK-3747 Servlet filter dependencies
2016-10-25 11:44:47 +02:00
Pavel Drozd 7882a6513c Merge pull request #3415 from vramik/KEYCLOAK-3489
KEYCLOAK-3489 add profile for testing migration for productized version
2016-10-25 11:07:02 +02:00
Stian Thorgersen 7e6c49fc74 Merge pull request #3413 from mstruk/KEYCLOAK-3801
KEYCLOAK-3801 Remove --unsafe from 'kcreg update'
2016-10-25 10:53:08 +02:00
Stian Thorgersen 765c3a7b0d Merge pull request #3418 from stianst/KEYCLOAK-3782
KEYCLOAK-3782 Keysize for rsa-generated should be a dropdown
2016-10-25 10:22:00 +02:00
Bas Dalenoord f3df185bb5 KEYCLOAK-3807: Calling 'setHandler' is forbidden
Use 'insertHandler' as suggested in the 'setHandler's log warning.
2016-10-25 09:14:03 +02:00
Stian Thorgersen 8c42167302 KEYCLOAK-3781 Don't allow deleting the last key provider 2016-10-25 08:57:16 +02:00
Stian Thorgersen 4b27e66714 KEYCLOAK-3782 Keysize for rsa-generated should be a dropdown 2016-10-25 08:52:02 +02:00
Bill Burke 3e28ac1e46 user spi cache policy 2016-10-24 15:36:37 -04:00
Vlasta Ramik 3ca836ffdc add profile for testing migration for productized version 2016-10-24 15:20:17 +02:00
zschwarz bc718471da KEYCLOAK-3747 Servlet filter dependencies 2016-10-24 15:01:16 +02:00
Marko Strukelj e24b27c79e KEYCLOAK-3801 Remove --unsafe from 'kcreg update' 2016-10-24 11:33:06 +02:00
Stan Silvert dcaac76b4b Merge pull request #3414 from ssilvert/cluster-node
KEYCLOAK-2206: Hide last registration field when adding new cluster node
2016-10-21 16:57:09 -04:00
Stan Silvert d741349830 KEYCLOAK-2206: Hide last registration field when adding new cluster node
for client.
2016-10-21 13:06:03 -04:00
Marek Posolda cd3f9ee27c Merge pull request #3407 from mposolda/KEYCLOAK-3792
KEYCLOAK-3792 Fix failing tests on MySQL
2016-10-21 13:47:48 +02:00
Marek Posolda 3320d34c2b Merge pull request #3406 from mposolda/master
KEYCLOAK-3779 ClientRegistrationPolicies test failing
2016-10-21 13:47:15 +02:00
Matej Lazar 036407fd90 Fix type in exception message. 2016-10-21 12:59:59 +02:00
Hynek Mlnarik 8bca84c0e7 KEYCLOAK-3793 Replace httpclient 4.4 calls with those available in 4.3 2016-10-21 11:34:08 +02:00
mposolda f7a6d39b01 KEYCLOAK-3792 Fix failing tests on MySQL 2016-10-21 11:21:01 +02:00
mposolda c79378ca5f KEYCLOAK-3779 ClientRegistrationPolicies test failing 2016-10-21 10:24:51 +02:00
Stian Thorgersen 4d47f758fc Merge pull request #3405 from stianst/master
Bump version
2016-10-21 10:11:59 +02:00
Stian Thorgersen e390cffa63 KEYCLOAK-3779
ClientRegistrationPoliciesTest failing on Travis
2016-10-21 08:11:11 +02:00
Stian Thorgersen c615674cbb Bump version 2016-10-21 07:03:15 +02:00
Stian Thorgersen 1a4f9e656d Merge pull request #3398 from stianst/KEYCLOAK-3774
KEYCLOAK-3774 Fix keycloak.js with prompt=none and new stricter redir…
2016-10-21 06:34:43 +02:00
Bill Burke e1a214351f Merge pull request #3391 from pulgupta/master
Null pointer exception after users logs in
2016-10-20 16:06:30 -04:00
Stian Thorgersen 9801f09a93 KEYCLOAK-3774 Fix keycloak.js with prompt=none and new stricter redirect_uri 2016-10-20 21:31:25 +02:00
Stian Thorgersen 9f8fb98083 Merge pull request #3382 from stianst/KEYCLOAK-3763
KEYCLOAK-3763
2016-10-20 21:24:11 +02:00
Bill Burke fd86f3bda8 Merge pull request #3399 from patriot1burke/master
realm cache event
2016-10-20 14:02:41 -04:00
Stian Thorgersen 390becb935 Merge pull request #3394 from hmlnarik/KEYCLOAK-3769
KEYCLOAK-3769 Workaround for ChangeLogService stale instance
2016-10-20 19:43:24 +02:00
Stian Thorgersen 7d8c79b17b Merge pull request #3397 from hmlnarik/KEYCLOAK-3775
KEYCLOAK-3775 Example: Add missing org.liquibase dependency to CLI command
2016-10-20 19:42:32 +02:00
Stian Thorgersen 772a1580ff Merge pull request #3403 from mposolda/master
KEYCLOAK-3773 Testsuite failing with mongo
2016-10-20 19:31:37 +02:00
Stian Thorgersen 5a00aaefa8 KEYCLOAK-2594
bind credential being leaked in admin tool JSON response

KEYCLOAK-2972
Keycloak leaks configuration passwords in Admin Event logs
2016-10-20 19:30:59 +02:00
Stian Thorgersen 1bf24d26a4 Merge pull request #3395 from stianst/master
KEYCLOAK-3772
2016-10-20 19:27:03 +02:00
Stian Thorgersen 284f49e584 Merge pull request #3396 from mstruk/KEYCLOAK-3740
KEYCLOAK-3740 kcreg.sh doesn't support symlinking
2016-10-20 19:26:53 +02:00
Stan Silvert e7ab53dd5f Merge pull request #3400 from ssilvert/title-addr-theme
KEYCLOAK-3776: Title for account management broken for address theme
2016-10-20 12:41:40 -04:00
Bill Burke 139158e614 fix 2016-10-20 12:36:24 -04:00
mposolda c4ad84945c KEYCLOAK-3773 Testsuite failing with mongo 2016-10-20 17:47:34 +02:00
Cherian Mathew 94d4afa11c Refactor entitlement request argument name 2016-10-20 17:24:41 +02:00
Cherian Mathew d7d91cfbc0 Add client api for requesting entitlements with permission requests 2016-10-20 17:09:41 +02:00
Stan Silvert 757d5c16df KEYCLOAK-3776: Title for account management broken for address theme 2016-10-20 10:38:21 -04:00
Bill Burke 36c2422fa4 realm cache event 2016-10-20 10:35:28 -04:00
Marek Posolda ec0f222f7e Merge pull request #3393 from mposolda/master
KEYCLOAK-3770 OIDC registration with id_token grant type should set p…
2016-10-20 16:35:08 +02:00
Hynek Mlnarik 969b44768a KEYCLOAK-3775 Example: Add missing org.liquibase dependency to CLI command 2016-10-20 15:35:08 +02:00
Marko Strukelj db0024d857 KEYCLOAK-3740 kcreg.sh doesn't support symlinking
- fix buggy patch
2016-10-20 15:05:17 +02:00
Hynek Mlnarik d59f6e397f KEYCLOAK-3769 Workaround for ChangeLogService stale instance
Before applying update or validation operation, Liquibase
ChangeLogService needs to be reset to forget about previously set
change log table. Reason is that the factory creating the
ChangeLogService caches this service per DB connection, not per
Liquibase object, hence changes in name of change log table needed for
custom JpaEntityProvider are not reflected and use only the first
change log table name, i.e. the change log table of the main database.
2016-10-20 14:57:51 +02:00
mposolda 072ccb5c61 KEYCLOAK-3770 OIDC registration with id_token grant type should set publicClient flag to true 2016-10-20 14:10:53 +02:00
Pulkit Gupta 8ee566f5fa Merge branch 'master' of github.com:pulgupta/keycloak 2016-10-20 13:39:54 +05:30
Pulkit Gupta 8e9db1be96 fixed null pointer exception when principal is null 2016-10-20 13:39:04 +05:30
Pulkit Gupta 115f95d90e fixed null pointer exception when principal is null 2016-10-20 13:36:25 +05:30
Cherian Mathew 2bba6af6d9 Include programmatically created resources in the resource cache 2016-10-19 11:04:22 +02:00
1368 changed files with 21301 additions and 6669 deletions

No files matched your search

+7 -1
View File
@@ -11,6 +11,12 @@ env:
global:
- MAVEN_SKIP_RC=true
- MAVEN_OPTS="-Xms512m -Xmx2048m"
matrix:
- TESTS=old
- TESTS=group1
- TESTS=group2
- TESTS=group3
- TESTS=adapter
jdk:
- oraclejdk8
@@ -22,6 +28,6 @@ install:
- travis_wait 60 mvn install -Pdistribution -DskipTests=true -B -V -q
script:
- mvn test -B
- ./travis-run-tests.sh $TESTS
sudo: false
+1 -1
View File
@@ -9,7 +9,7 @@ For more information about Keycloak visit [Keycloak homepage](http://keycloak.or
Building
--------
Ensure you have JDK 8 (or newer), Maven 3.2.1 (or newer) and Git installed
Ensure you have JDK 8 (or newer), Maven 3.1.1 (or newer) and Git installed
java -version
mvn -version
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -142,9 +142,13 @@ public class AuthenticatedActionsHandler {
AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
session.setAuthorizationContext(authorizationContext);
if (session != null) {
session.setAuthorizationContext(authorizationContext);
return authorizationContext.isGranted();
return authorizationContext.isGranted();
}
return true;
} catch (Exception e) {
throw new RuntimeException("Failed to enforce policy decisions.", e);
}
@@ -38,7 +38,7 @@ import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.keycloak.common.util.EnvUtil;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.representations.adapters.config.AdapterHttpClientConfig;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -333,7 +333,7 @@ public class HttpClientBuilder {
}
}
public HttpClient build(AdapterConfig adapterConfig) {
public HttpClient build(AdapterHttpClientConfig adapterConfig) {
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
String truststorePath = adapterConfig.getTruststore();
@@ -379,13 +379,13 @@ public class HttpClientBuilder {
/**
* Configures a the proxy to use for auth-server requests if provided.
* <p>
* If the given {@link AdapterConfig} contains the attribute {@code proxy-url} we use the
* If the given {@link AdapterHttpClientConfig} contains the attribute {@code proxy-url} we use the
* given URL as a proxy server, otherwise the proxy configuration is ignored.
* </p>
*
* @param adapterConfig
*/
private void configureProxyForAuthServerIfProvided(AdapterConfig adapterConfig) {
private void configureProxyForAuthServerIfProvided(AdapterHttpClientConfig adapterConfig) {
if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) {
return;
@@ -19,6 +19,7 @@ package org.keycloak.adapters.authorization;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
@@ -66,40 +67,51 @@ public abstract class AbstractPolicyEnforcer {
return createEmptyAuthorizationContext(true);
}
AccessToken accessToken = httpFacade.getSecurityContext().getToken();
Request request = httpFacade.getRequest();
Response response = httpFacade.getResponse();
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
if (securityContext != null) {
AccessToken accessToken = securityContext.getToken();
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken);
if (accessToken != null) {
Request request = httpFacade.getRequest();
Response response = httpFacade.getResponse();
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken);
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
response.sendError(403, "Could not find a configuration for path [" + path + "].");
return createEmptyAuthorizationContext(false);
}
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
return createEmptyAuthorizationContext(true);
}
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
}
}
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
response.sendError(403, "Authorization failed.");
}
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
response.sendError(403, "Could not find a configuration for path [" + path + "].");
return createEmptyAuthorizationContext(false);
}
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
}
}
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
response.sendError(403, "Authorization failed.");
}
return createEmptyAuthorizationContext(false);
@@ -110,7 +122,7 @@ public abstract class AbstractPolicyEnforcer {
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
Request request = httpFacade.getRequest();
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
String accessDeniedPath = enforcerConfig.getAccessDeniedPath();
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
if (accessDeniedPath != null) {
if (request.getURI().contains(accessDeniedPath)) {
@@ -125,14 +137,17 @@ public abstract class AbstractPolicyEnforcer {
}
List<Permission> permissions = authorization.getPermissions();
boolean hasPermission = false;
for (Permission permission : permissions) {
if (permission.getResourceSetId() != null) {
if (isResourcePermission(actualPathConfig, permission)) {
hasPermission = true;
if (actualPathConfig.isInstance() && !matchResourcePermission(actualPathConfig, permission)) {
continue;
}
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
@@ -143,11 +158,16 @@ public abstract class AbstractPolicyEnforcer {
}
} else {
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
hasPermission = true;
return true;
}
}
}
if (!hasPermission && EnforcementMode.PERMISSIVE.equals(actualPathConfig.getEnforcementMode())) {
return true;
}
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
return false;
@@ -218,6 +238,7 @@ public abstract class AbstractPolicyEnforcer {
config.setScopes(originalConfig.getScopes());
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
config.setEnforcementMode(originalConfig.getEnforcementMode());
this.paths.add(config);
@@ -41,7 +41,7 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
@Override
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
} else {
challengeEntitlementAuthentication(facade);
@@ -88,7 +88,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
@Override
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
String accessDeniedPath = getEnforcerConfig().getAccessDeniedPath();
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
HttpFacade.Response response = facade.getResponse();
if (accessDeniedPath != null) {
@@ -107,7 +107,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
AuthzClient authzClient = getAuthzClient();
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
LOGGER.debug("Obtaining authorization for authenticated user.");
PermissionRequest permissionRequest = new PermissionRequest();
@@ -105,7 +105,16 @@ public class PolicyEnforcer {
}
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
if (enforcerConfig.getPaths().isEmpty()) {
boolean loadPathsFromServer = true;
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
if (!PolicyEnforcerConfig.EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
loadPathsFromServer = false;
break;
}
}
if (loadPathsFromServer) {
LOGGER.info("No path provided in configuration.");
return configureAllPathsForResourceServer(protectedResource);
} else {
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -86,7 +86,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
list.add(addRealm);
@@ -117,7 +117,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
* TODO need to check realm-ref first.
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
*/
@@ -46,7 +46,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
//TODO: externalize message
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -118,12 +118,11 @@
/**
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
*/
this.entitlement = function (resourceSeververId) {
this.entitlement = function (resourceSeververId, entitlementRequest ) {
this.then = function (onGrant, onDeny, onError) {
var request = new XMLHttpRequest();
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.onreadystatechange = function () {
if (request.readyState == 4) {
@@ -149,7 +148,19 @@
}
};
request.send(null);
var erJson = null
if(entitlementRequest) {
request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
request.setRequestHeader("Content-type", "application/json");
erJson = JSON.stringify(entitlementRequest)
} else {
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
}
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.send(erJson);
};
return this;
@@ -210,11 +210,18 @@
var nonce = createUUID();
var redirectUri = adapter.redirectUri(options);
if (options && options.prompt) {
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'prompt=' + options.prompt;
var callbackState = {
state: state,
nonce: nonce,
redirectUri: encodeURIComponent(redirectUri),
}
callbackStorage.add({ state: state, nonce: nonce, redirectUri: encodeURIComponent(redirectUri) });
if (options && options.prompt) {
callbackState.prompt = options.prompt;
}
callbackStorage.add(callbackState);
var action = 'auth';
if (options && options.action == 'register') {
@@ -747,6 +754,7 @@
if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
oauth.redirectUri = oauthState.redirectUri;
oauth.storedNonce = oauthState.nonce;
oauth.prompt = oauthState.prompt;
if (oauth.fragment) {
oauth.newUrl += '#' + oauth.fragment;
@@ -1041,7 +1049,7 @@
function clearExpired() {
var time = new Date().getTime();
for (var i = 1; i <= localStorage.length; i++) {
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (key && key.indexOf('kc-callback-') == 0) {
var value = localStorage.getItem(key);
@@ -1218,9 +1226,6 @@
case 'redirect_fragment':
oauth.fragment = queryParams[param];
break;
case 'prompt':
oauth.prompt = queryParams[param];
break;
default:
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
@@ -21,13 +21,16 @@
var init;
function checkState(clientId, origin, sessionState, callback) {
if (!init) {
var cookie = getCookie();
if (!cookie) {
callback('changed');
} else if (!init) {
var req = new XMLHttpRequest();
var url = location.href + "/init";
url += "?client_id=" + encodeURIComponent(clientId);
url += "&origin=" + encodeURIComponent(origin);
url += "&session_state=" + encodeURIComponent(sessionState);
req.open('GET', url, true);
@@ -50,7 +53,6 @@
req.send();
} else {
if (clientId == init.clientId && origin == init.origin) {
var cookie = getCookie();
if (sessionState == cookie) {
callback('unchanged');
} else {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -215,7 +215,7 @@ public class KeycloakSpringBootConfiguration {
securityHandler.setConstraintMappings(jettyConstraintMappings);
securityHandler.setAuthenticator(keycloakJettyAuthenticator);
webAppContext.setHandler(securityHandler);
webAppContext.setSecurityHandler(securityHandler);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -127,7 +127,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
InputStream configInputStream = getConfigInputStream(context);
KeycloakDeployment kd;
if (configInputStream == null) {
log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
log.warning("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
kd = new KeycloakDeployment();
} else {
kd = KeycloakDeploymentBuilder.build(configInputStream);
@@ -196,6 +196,8 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
if (deployment == null || !deployment.isConfigured()) {
//needed for the EAP6/AS7 adapter relying on the tomcat core adapter
facade.getResponse().sendError(401);
return false;
}
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -39,9 +39,20 @@ import java.util.List;
* @version $Revision: 1 $
*/
public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorValve {
/**
* Method called by Tomcat < 8.5.5
*/
public boolean authenticate(Request request, HttpServletResponse response) throws IOException {
return authenticateInternal(request, response, request.getContext().getLoginConfig());
}
/**
* Method called by Tomcat >= 8.5.5
*/
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
return this.authenticate(request, response);
}
@Override
protected boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -92,7 +92,7 @@ public abstract class AbstractUndertowKeycloakAuthMech implements Authentication
UndertowHttpFacade facade = createFacade(exchange);
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
KeycloakSecurityContext ksc = exchange.getAttachment(OIDCUndertowHttpFacade.KEYCLOAK_SECURITY_CONTEXT_KEY);
if (ksc != null && ksc instanceof RefreshableKeycloakSecurityContext) {
if (!deployment.isBearerOnly() && ksc != null && ksc instanceof RefreshableKeycloakSecurityContext) {
((RefreshableKeycloakSecurityContext) ksc).logout(deployment);
}
AdapterTokenStore tokenStore = getTokenStore(exchange, facade, deployment, securityContext);
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak WildFly Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -87,7 +87,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addRealm)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
list.add(addRealm);
@@ -118,7 +118,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
* TODO need to check realm-ref first.
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(addSecureDeployment)) {
//TODO: externalize the message
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new XMLStreamException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
*/
@@ -54,7 +54,7 @@ public final class RealmAddHandler extends AbstractAddStepHandler {
if (!SharedAttributeDefinitons.validateTruststoreSetIfRequired(model.clone())) {
//TODO: externalize message
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-maanger is false.");
throw new OperationFailedException("truststore and truststore-password must be set if ssl-required is not none and disable-trust-manager is false.");
}
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Keycloak Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML EAP Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -105,7 +105,7 @@ public class SamlPrincipal implements Serializable, Principal {
* @return
*/
public List<String> getFriendlyAttributes(String friendlyName) {
List<String> list = friendlyAttributes.get(name);
List<String> list = friendlyAttributes.get(friendlyName);
if (list != null) {
return Collections.unmodifiableList(list);
} else {
Whitespace-only changes.
+7 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -34,6 +34,7 @@
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
@@ -70,6 +71,11 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
@@ -0,0 +1,75 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.cloned;
/**
* Configuration options relevant for configuring http client that can be used by adapter.
*
* NOTE: keep in sync with core/src/main/java/org/keycloak/representations/adapters/config/AdapterHttpClientConfig.java until unified.
*
* @author hmlnarik
*/
public interface AdapterHttpClientConfig {
/**
* Returns truststore filename.
*/
public String getTruststore();
/**
* Returns truststore password.
*/
public String getTruststorePassword();
/**
* Returns keystore with client keys.
*/
public String getClientKeystore();
/**
* Returns keystore password.
*/
public String getClientKeystorePassword();
/**
* Returns boolean flag whether any hostname verification is done on the server's
* certificate, {@code true} means that verification is not done.
* @return
*/
public boolean isAllowAnyHostname();
/**
* Returns boolean flag whether any trust management and hostname verification is done.
* <p>
* <i>NOTE</i> Disabling trust manager is a security hole, so only set this option
* if you cannot or do not want to verify the identity of the
* host you are communicating with.
*/
public boolean isDisableTrustManager();
/**
* Returns size of connection pool.
*/
public int getConnectionPoolSize();
/**
* Returns URL of HTTP proxy.
*/
public String getProxyUrl();
}
@@ -0,0 +1,78 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.cloned;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.util.EntityUtils;
import org.keycloak.adapters.saml.descriptor.parsers.SamlDescriptorIDPKeysExtractor;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.saml.common.exceptions.ParsingException;
/**
* @author <a href="mailto:hmlnarik@redhat.com">Hynek Mlnařík</a>
*/
public class HttpAdapterUtils {
public static MultivaluedHashMap<String, KeyInfo> downloadKeysFromSamlDescriptor(HttpClient client, String descriptorUrl) throws HttpClientAdapterException {
try {
HttpGet httpRequest = new HttpGet(descriptorUrl);
HttpResponse response = client.execute(httpRequest);
int status = response.getStatusLine().getStatusCode();
if (status != HttpStatus.SC_OK) {
EntityUtils.consumeQuietly(response.getEntity());
throw new HttpClientAdapterException("Unexpected status = " + status);
}
HttpEntity entity = response.getEntity();
if (entity == null) {
throw new HttpClientAdapterException("There was no entity.");
}
MultivaluedHashMap<String, KeyInfo> res;
try (InputStream is = entity.getContent()) {
res = extractKeysFromSamlDescriptor(is);
}
EntityUtils.consumeQuietly(entity);
return res;
} catch (IOException | ParsingException e) {
throw new HttpClientAdapterException("IO error", e);
}
}
/**
* Parses SAML descriptor and extracts keys from it.
* @param xmlStream
* @return List of KeyInfo objects containing keys from the descriptor.
* @throws IOException
*/
public static MultivaluedHashMap<String, KeyInfo> extractKeysFromSamlDescriptor(InputStream xmlStream) throws ParsingException {
Object res = new SamlDescriptorIDPKeysExtractor().parse(xmlStream);
return (MultivaluedHashMap<String, KeyInfo>) res;
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.cloned;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class HttpClientAdapterException extends Exception {
public HttpClientAdapterException(String message) {
super(message);
}
public HttpClientAdapterException(String message, Throwable t) {
super(message, t);
}
}
@@ -0,0 +1,396 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.cloned;
import org.apache.http.HttpHost;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.keycloak.common.util.EnvUtil;
import org.keycloak.common.util.KeystoreUtil;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URI;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Abstraction for creating HttpClients. Allows SSL configuration.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class HttpClientBuilder {
public static enum HostnameVerificationPolicy {
/**
* Hostname verification is not done on the server's certificate
*/
ANY,
/**
* Allows wildcards in subdomain names i.e. *.foo.com
*/
WILDCARD,
/**
* CN must match hostname connecting to
*/
STRICT
}
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
private static class PassthroughTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
protected KeyStore truststore;
protected KeyStore clientKeyStore;
protected String clientPrivateKeyPassword;
protected boolean disableTrustManager;
protected boolean disableCookieCache = true;
protected HostnameVerificationPolicy policy = HostnameVerificationPolicy.WILDCARD;
protected SSLContext sslContext;
protected int connectionPoolSize = 100;
protected int maxPooledPerRoute = 0;
protected long connectionTTL = -1;
protected TimeUnit connectionTTLUnit = TimeUnit.MILLISECONDS;
protected HostnameVerifier verifier = null;
protected long socketTimeout = -1;
protected TimeUnit socketTimeoutUnits = TimeUnit.MILLISECONDS;
protected long establishConnectionTimeout = -1;
protected TimeUnit establishConnectionTimeoutUnits = TimeUnit.MILLISECONDS;
protected HttpHost proxyHost;
/**
* Socket inactivity timeout
*
* @param timeout
* @param unit
* @return
*/
public HttpClientBuilder socketTimeout(long timeout, TimeUnit unit) {
this.socketTimeout = timeout;
this.socketTimeoutUnits = unit;
return this;
}
/**
* When trying to make an initial socket connection, what is the timeout?
*
* @param timeout
* @param unit
* @return
*/
public HttpClientBuilder establishConnectionTimeout(long timeout, TimeUnit unit) {
this.establishConnectionTimeout = timeout;
this.establishConnectionTimeoutUnits = unit;
return this;
}
public HttpClientBuilder connectionTTL(long ttl, TimeUnit unit) {
this.connectionTTL = ttl;
this.connectionTTLUnit = unit;
return this;
}
public HttpClientBuilder maxPooledPerRoute(int maxPooledPerRoute) {
this.maxPooledPerRoute = maxPooledPerRoute;
return this;
}
public HttpClientBuilder connectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
return this;
}
/**
* Disable trust management and hostname verification. <i>NOTE</i> this is a security
* hole, so only set this option if you cannot or do not want to verify the identity of the
* host you are communicating with.
*/
public HttpClientBuilder disableTrustManager() {
this.disableTrustManager = true;
return this;
}
public HttpClientBuilder disableCookieCache() {
this.disableCookieCache = true;
return this;
}
/**
* SSL policy used to verify hostnames
*
* @param policy
* @return
*/
public HttpClientBuilder hostnameVerification(HostnameVerificationPolicy policy) {
this.policy = policy;
return this;
}
public HttpClientBuilder sslContext(SSLContext sslContext) {
this.sslContext = sslContext;
return this;
}
public HttpClientBuilder trustStore(KeyStore truststore) {
this.truststore = truststore;
return this;
}
public HttpClientBuilder keyStore(KeyStore keyStore, String password) {
this.clientKeyStore = keyStore;
this.clientPrivateKeyPassword = password;
return this;
}
public HttpClientBuilder keyStore(KeyStore keyStore, char[] password) {
this.clientKeyStore = keyStore;
this.clientPrivateKeyPassword = new String(password);
return this;
}
static class VerifierWrapper implements X509HostnameVerifier {
protected HostnameVerifier verifier;
VerifierWrapper(HostnameVerifier verifier) {
this.verifier = verifier;
}
@Override
public void verify(String host, SSLSocket ssl) throws IOException {
if (!verifier.verify(host, ssl.getSession())) throw new SSLException("Hostname verification failure");
}
@Override
public void verify(String host, X509Certificate cert) throws SSLException {
throw new SSLException("This verification path not implemented");
}
@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
throw new SSLException("This verification path not implemented");
}
@Override
public boolean verify(String s, SSLSession sslSession) {
return verifier.verify(s, sslSession);
}
}
public HttpClient build() {
X509HostnameVerifier verifier = null;
if (this.verifier != null) verifier = new VerifierWrapper(this.verifier);
else {
switch (policy) {
case ANY:
verifier = new AllowAllHostnameVerifier();
break;
case WILDCARD:
verifier = new BrowserCompatHostnameVerifier();
break;
case STRICT:
verifier = new StrictHostnameVerifier();
break;
}
}
try {
SSLSocketFactory sslsf = null;
SSLContext theContext = sslContext;
if (disableTrustManager) {
theContext = SSLContext.getInstance("SSL");
theContext.init(null, new TrustManager[]{new PassthroughTrustManager()},
new SecureRandom());
verifier = new AllowAllHostnameVerifier();
sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (theContext != null) {
sslsf = new SniSSLSocketFactory(theContext, verifier);
} else if (clientKeyStore != null || truststore != null) {
sslsf = new SniSSLSocketFactory(SSLSocketFactory.TLS, clientKeyStore, clientPrivateKeyPassword, truststore, null, verifier);
} else {
final SSLContext tlsContext = SSLContext.getInstance(SSLSocketFactory.TLS);
tlsContext.init(null, null, null);
sslsf = new SniSSLSocketFactory(tlsContext, verifier);
}
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
Scheme httpsScheme = new Scheme("https", 443, sslsf);
registry.register(httpsScheme);
ClientConnectionManager cm = null;
if (connectionPoolSize > 0) {
ThreadSafeClientConnManager tcm = new ThreadSafeClientConnManager(registry, connectionTTL, connectionTTLUnit);
tcm.setMaxTotal(connectionPoolSize);
if (maxPooledPerRoute == 0) maxPooledPerRoute = connectionPoolSize;
tcm.setDefaultMaxPerRoute(maxPooledPerRoute);
cm = tcm;
} else {
cm = new SingleClientConnManager(registry);
}
BasicHttpParams params = new BasicHttpParams();
if (proxyHost != null) {
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
}
if (socketTimeout > -1) {
HttpConnectionParams.setSoTimeout(params, (int) socketTimeoutUnits.toMillis(socketTimeout));
}
if (establishConnectionTimeout > -1) {
HttpConnectionParams.setConnectionTimeout(params, (int) establishConnectionTimeoutUnits.toMillis(establishConnectionTimeout));
}
DefaultHttpClient client = new DefaultHttpClient(cm, params);
if (disableCookieCache) {
client.setCookieStore(new CookieStore() {
@Override
public void addCookie(Cookie cookie) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<Cookie> getCookies() {
return Collections.emptyList();
}
@Override
public boolean clearExpired(Date date) {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void clear() {
//To change body of implemented methods use File | Settings | File Templates.
}
});
}
return client;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public HttpClient build(AdapterHttpClientConfig adapterConfig) {
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
String truststorePath = adapterConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = adapterConfig.getTruststorePassword();
try {
this.truststore = KeystoreUtil.loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
String clientKeystore = adapterConfig.getClientKeystore();
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
try {
KeyStore clientCertKeystore = KeystoreUtil.loadKeyStore(clientKeystore, clientKeystorePassword);
keyStore(clientCertKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
int size = 10;
if (adapterConfig.getConnectionPoolSize() > 0)
size = adapterConfig.getConnectionPoolSize();
HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (adapterConfig.isAllowAnyHostname())
policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
connectionPoolSize(size);
hostnameVerification(policy);
if (adapterConfig.isDisableTrustManager()) {
disableTrustManager();
} else {
trustStore(truststore);
}
configureProxyForAuthServerIfProvided(adapterConfig);
return build();
}
/**
* Configures a the proxy to use for auth-server requests if provided.
* <p>
* If the given {@link AdapterHttpClientConfig} contains the attribute {@code proxy-url} we use the
* given URL as a proxy server, otherwise the proxy configuration is ignored.
* </p>
*
* @param adapterConfig
*/
private void configureProxyForAuthServerIfProvided(AdapterHttpClientConfig adapterConfig) {
if (adapterConfig == null || adapterConfig.getProxyUrl() == null || adapterConfig.getProxyUrl().trim().isEmpty()) {
return;
}
URI uri = URI.create(adapterConfig.getProxyUrl());
this.proxyHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
}
}
@@ -0,0 +1,143 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.cloned;
import org.apache.http.HttpHost;
import org.apache.http.conn.scheme.HostNameResolver;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.protocol.HttpContext;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.AccessController;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* SSLSocketFactory that uses Server Name Indication (SNI) TLS extension.
*
* <p>
* Originally copied from <b>keycloak-adapter-core</b> project.
*
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
* @author <a href="mailto:hmlnarik@redhat.com">Hynek Mlnařík</a>
*/
public class SniSSLSocketFactory extends SSLSocketFactory {
private static final Logger LOG = Logger.getLogger(SniSSLSocketFactory.class.getName());
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, HostNameResolver nameResolver) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, nameResolver);
}
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, trustStrategy, hostnameVerifier);
}
public SniSSLSocketFactory(String algorithm, KeyStore keystore, String keyPassword, KeyStore truststore, SecureRandom random, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(algorithm, keystore, keyPassword, truststore, random, hostnameVerifier);
}
public SniSSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keystorePassword, truststore);
}
public SniSSLSocketFactory(KeyStore keystore, String keystorePassword) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(keystore, keystorePassword);
}
public SniSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
}
public SniSSLSocketFactory(TrustStrategy trustStrategy, X509HostnameVerifier hostnameVerifier) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(trustStrategy, hostnameVerifier);
}
public SniSSLSocketFactory(TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(trustStrategy);
}
public SniSSLSocketFactory(SSLContext sslContext) {
super(sslContext);
}
public SniSSLSocketFactory(SSLContext sslContext, HostNameResolver nameResolver) {
super(sslContext, nameResolver);
}
public SniSSLSocketFactory(SSLContext sslContext, X509HostnameVerifier hostnameVerifier) {
super(sslContext, hostnameVerifier);
}
public SniSSLSocketFactory(SSLContext sslContext, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier) {
super(socketfactory, hostnameVerifier);
}
public SniSSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory, String[] supportedProtocols, String[] supportedCipherSuites, X509HostnameVerifier hostnameVerifier) {
super(socketfactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
}
@Override
public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context) throws IOException {
return super.connectSocket(connectTimeout, applySNI(socket, host.getHostName()), host, remoteAddress, localAddress, context);
}
@Override
public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
return super.createLayeredSocket(applySNI(socket, target), target, port, context);
}
private Socket applySNI(final Socket socket, String hostname) {
if (socket instanceof SSLSocket) {
try {
Method setHostMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
@Override
public Method run() throws NoSuchMethodException {
return socket.getClass().getMethod("setHost", String.class);
}
});
setHostMethod.invoke(socket, hostname);
LOG.log(Level.FINEST, "Applied SNI to socket for host {0}", hostname);
} catch (PrivilegedActionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOG.log(Level.WARNING, "Failed to apply SNI to SSLSocket", e);
}
}
return socket;
}
}
@@ -79,7 +79,9 @@ public abstract class AbstractInitiateLogin implements AuthChallenge {
binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
}
binding.signWith(keypair);
binding.signWith(null, keypair);
// TODO: As part of KEYCLOAK-3810, add KeyID to the SAML document
// <related DocumentBuilder>.addExtension(new KeycloakKeySamlExtensionGenerator(<key ID>));
binding.signDocument();
}
return binding;
@@ -23,7 +23,14 @@ import org.keycloak.saml.SignatureAlgorithm;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.http.client.HttpClient;
import org.keycloak.adapters.saml.rotation.SamlDescriptorPublicKeyLocator;
import org.keycloak.rotation.CompositeKeyLocator;
import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -179,10 +186,15 @@ public class DefaultSamlDeployment implements SamlDeployment {
public static class DefaultIDP implements IDP {
private static final int DEFAULT_CACHE_TTL = 24 * 60 * 60;
private String entityID;
private PublicKey signatureValidationKey;
private final CompositeKeyLocator signatureValidationKeyLocator = new CompositeKeyLocator();
private SingleSignOnService singleSignOnService;
private SingleLogoutService singleLogoutService;
private final List<PublicKey> signatureValidationKeys = new LinkedList<>();
private int minTimeBetweenDescriptorRequests;
private HttpClient client;
@Override
public String getEntityID() {
@@ -200,16 +212,25 @@ public class DefaultSamlDeployment implements SamlDeployment {
}
@Override
public PublicKey getSignatureValidationKey() {
return signatureValidationKey;
public KeyLocator getSignatureValidationKeyLocator() {
return this.signatureValidationKeyLocator;
}
@Override
public int getMinTimeBetweenDescriptorRequests() {
return minTimeBetweenDescriptorRequests;
}
public void setMinTimeBetweenDescriptorRequests(int minTimeBetweenDescriptorRequests) {
this.minTimeBetweenDescriptorRequests = minTimeBetweenDescriptorRequests;
}
public void setEntityID(String entityID) {
this.entityID = entityID;
}
public void setSignatureValidationKey(PublicKey signatureValidationKey) {
this.signatureValidationKey = signatureValidationKey;
public void addSignatureValidationKey(PublicKey signatureValidationKey) {
this.signatureValidationKeys.add(signatureValidationKey);
}
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
@@ -219,6 +240,31 @@ public class DefaultSamlDeployment implements SamlDeployment {
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
this.singleLogoutService = singleLogoutService;
}
public void refreshKeyLocatorConfiguration() {
this.signatureValidationKeyLocator.clear();
// When key is set, use that (and only that), otherwise configure dynamic key locator
if (! this.signatureValidationKeys.isEmpty()) {
this.signatureValidationKeyLocator.add(new HardcodedKeyLocator(this.signatureValidationKeys));
} else if (this.singleSignOnService != null) {
String samlDescriptorUrl = singleSignOnService.getRequestBindingUrl() + "/descriptor";
HttpClient httpClient = getClient();
SamlDescriptorPublicKeyLocator samlDescriptorPublicKeyLocator =
new SamlDescriptorPublicKeyLocator(
samlDescriptorUrl, this.minTimeBetweenDescriptorRequests, DEFAULT_CACHE_TTL, httpClient);
this.signatureValidationKeyLocator.add(samlDescriptorPublicKeyLocator);
}
}
@Override
public HttpClient getClient() {
return this.client;
}
public void setClient(HttpClient client) {
this.client = client;
}
}
private IDP idp;
@@ -22,14 +22,18 @@ import org.keycloak.saml.SignatureAlgorithm;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Set;
import org.apache.http.client.HttpClient;
import org.keycloak.rotation.KeyLocator;
/**
* Represents SAML deployment configuration.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface SamlDeployment {
enum Binding {
POST,
REDIRECT;
@@ -41,20 +45,68 @@ public interface SamlDeployment {
}
public interface IDP {
/**
* Returns entity identifier of this IdP.
* @return see description.
*/
String getEntityID();
/**
* Returns Single sign on service configuration for this IdP.
* @return see description.
*/
SingleSignOnService getSingleSignOnService();
/**
* Returns Single logout service configuration for this IdP.
* @return see description.
*/
SingleLogoutService getSingleLogoutService();
PublicKey getSignatureValidationKey();
/**
* Returns {@link KeyLocator} looking up public keys used for validation of IdP signatures.
* @return see description.
*/
KeyLocator getSignatureValidationKeyLocator();
/**
* Returns minimum time (in seconds) between issuing requests to IdP SAML descriptor.
* Used e.g. by {@link KeyLocator} looking up public keys for validation of IdP signatures
* to prevent too frequent requests.
*
* @return see description.
*/
int getMinTimeBetweenDescriptorRequests();
/**
* Returns {@link HttpClient} instance that will be used for http communication with this IdP.
* @return see description
*/
HttpClient getClient();
public interface SingleSignOnService {
/**
* Returns {@code true} if the requests to IdP need to be signed by SP key.
* @return see dscription
*/
boolean signRequest();
/**
* Returns {@code true} if the complete response message from IdP should
* be checked for valid signature.
* @return see dscription
*/
boolean validateResponseSignature();
/**
* Returns {@code true} if individual assertions in response from IdP should
* be checked for valid signature.
* @return see dscription
*/
boolean validateAssertionSignature();
Binding getRequestBinding();
Binding getResponseBinding();
String getRequestBindingUrl();
}
public interface SingleLogoutService {
boolean validateRequestSignature();
boolean validateResponseSignature();
@@ -67,10 +119,19 @@ public interface SamlDeployment {
}
}
/**
* Returns Identity Provider configuration for this SAML deployment.
* @return see description.
*/
public IDP getIDP();
public boolean isConfigured();
SslRequired getSslRequired();
/**
* Returns entity identifier of this SP.
* @return see description.
*/
String getEntityID();
String getNameIDPolicyFormat();
boolean isForceAuthentication();
@@ -19,6 +19,7 @@ package org.keycloak.adapters.saml.config;
import java.io.Serializable;
import java.util.List;
import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -157,12 +158,97 @@ public class IDP implements Serializable {
}
}
public static class HttpClientConfig implements AdapterHttpClientConfig {
private String truststore;
private String truststorePassword;
private String clientKeystore;
private String clientKeystorePassword;
private boolean allowAnyHostname;
private boolean disableTrustManager;
private int connectionPoolSize;
private String proxyUrl;
@Override
public String getTruststore() {
return truststore;
}
public void setTruststore(String truststore) {
this.truststore = truststore;
}
@Override
public String getTruststorePassword() {
return truststorePassword;
}
public void setTruststorePassword(String truststorePassword) {
this.truststorePassword = truststorePassword;
}
@Override
public String getClientKeystore() {
return clientKeystore;
}
public void setClientKeystore(String clientKeystore) {
this.clientKeystore = clientKeystore;
}
@Override
public String getClientKeystorePassword() {
return clientKeystorePassword;
}
public void setClientKeystorePassword(String clientKeystorePassword) {
this.clientKeystorePassword = clientKeystorePassword;
}
@Override
public boolean isAllowAnyHostname() {
return allowAnyHostname;
}
public void setAllowAnyHostname(boolean allowAnyHostname) {
this.allowAnyHostname = allowAnyHostname;
}
@Override
public boolean isDisableTrustManager() {
return disableTrustManager;
}
public void setDisableTrustManager(boolean disableTrustManager) {
this.disableTrustManager = disableTrustManager;
}
@Override
public int getConnectionPoolSize() {
return connectionPoolSize;
}
public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
}
@Override
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
}
private String entityID;
private String signatureAlgorithm;
private String signatureCanonicalizationMethod;
private SingleSignOnService singleSignOnService;
private SingleLogoutService singleLogoutService;
private List<Key> keys;
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
public String getEntityID() {
return entityID;
@@ -212,4 +298,12 @@ public class IDP implements Serializable {
this.signatureCanonicalizationMethod = signatureCanonicalizationMethod;
}
public AdapterHttpClientConfig getHttpClientConfig() {
return httpClientConfig;
}
public void setHttpClientConfig(AdapterHttpClientConfig httpClientConfig) {
this.httpClientConfig = httpClientConfig;
}
}
@@ -72,4 +72,15 @@ public class ConfigXmlConstants {
public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
public static final String HTTP_CLIENT_ELEMENT = "HttpClient";
public static final String ALLOW_ANY_HOSTNAME_ATTR = "allowAnyHostname";
public static final String CLIENT_KEYSTORE_ATTR = "clientKeystore";
public static final String CLIENT_KEYSTORE_PASSWORD_ATTR = "clientKeystorePassword";
public static final String CONNECTION_POOL_SIZE_ATTR = "connectionPoolSize";
public static final String DISABLE_TRUST_MANAGER_ATTR = "disableTrustManager";
public static final String PROXY_URL_ATTR = "proxyUrl";
public static final String TRUSTSTORE_ATTR = "truststore";
public static final String TRUSTSTORE_PASSWORD_ATTR = "truststorePassword";
}
@@ -40,6 +40,7 @@ import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.HashSet;
import java.util.Set;
import org.keycloak.adapters.cloned.HttpClientBuilder;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -178,35 +179,39 @@ public class DeploymentBuilder {
if (sp.getIdp().getKeys() != null) {
for (Key key : sp.getIdp().getKeys()) {
if (key.isSigning()) {
if (key.getKeystore() != null) {
KeyStore keyStore = loadKeystore(resourceLoader, key);
Certificate cert = null;
try {
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
idp.setSignatureValidationKey(cert.getPublicKey());
} else {
if (key.getPublicKeyPem() == null && key.getCertificatePem() == null) {
throw new RuntimeException("IDP signing key must have a PublicKey or Certificate defined");
}
try {
PublicKey publicKey = getPublicKeyFromPem(key);
idp.setSignatureValidationKey(publicKey);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
processSigningKey(idp, key, resourceLoader);
}
}
}
idp.setClient(new HttpClientBuilder().build(sp.getIdp().getHttpClientConfig()));
idp.refreshKeyLocatorConfiguration();
return deployment;
}
protected static PublicKey getPublicKeyFromPem(Key key) throws Exception {
private void processSigningKey(DefaultSamlDeployment.DefaultIDP idp, Key key, ResourceLoader resourceLoader) throws RuntimeException {
PublicKey publicKey;
if (key.getKeystore() != null) {
KeyStore keyStore = loadKeystore(resourceLoader, key);
Certificate cert = null;
try {
cert = keyStore.getCertificate(key.getKeystore().getCertificateAlias());
} catch (KeyStoreException e) {
throw new RuntimeException(e);
}
publicKey = cert.getPublicKey();
} else {
if (key.getPublicKeyPem() == null && key.getCertificatePem() == null) {
throw new RuntimeException("IDP signing key must have a PublicKey or Certificate defined");
}
publicKey = getPublicKeyFromPem(key);
}
idp.addSignatureValidationKey(publicKey);
}
protected static PublicKey getPublicKeyFromPem(Key key) {
PublicKey publicKey;
if (key.getPublicKeyPem() != null) {
publicKey = PemUtils.decodePublicKey(key.getPublicKeyPem().trim());
@@ -29,6 +29,10 @@ import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.util.List;
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getAttributeValue;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getBooleanAttributeValue;
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getIntegerAttributeValue;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -41,16 +45,16 @@ public class IDPXmlParser extends AbstractParser {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
IDP idp = new IDP();
String entityID = SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
if (entityID == null) {
throw new ParsingException("entityID must be set on IDP");
}
idp.setEntityID(entityID);
boolean signaturesRequired = SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
idp.setSignatureCanonicalizationMethod(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
idp.setSignatureAlgorithm(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
boolean signaturesRequired = getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
idp.setSignatureCanonicalizationMethod(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
idp.setSignatureAlgorithm(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
@@ -75,6 +79,10 @@ public class IDPXmlParser extends AbstractParser {
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
idp.setSingleLogoutService(slo);
} else if (tag.equals(ConfigXmlConstants.HTTP_CLIENT_ELEMENT)) {
HttpClientConfig config = parseHttpClientElement(xmlEventReader);
idp.setHttpClientConfig(config);
} else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
KeysXmlParser parser = new KeysXmlParser();
List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
@@ -90,29 +98,63 @@ public class IDPXmlParser extends AbstractParser {
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
slo.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
slo.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
slo.setValidateRequestSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
slo.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
slo.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
slo.setSignResponse(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
slo.setPostBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
slo.setRedirectBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
slo.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
slo.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
slo.setValidateRequestSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
slo.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
slo.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
slo.setSignResponse(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
slo.setPostBindingUrl(getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
slo.setRedirectBindingUrl(getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
return slo;
}
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
sso.setValidateAssertionSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
sso.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
sso.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
sso.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
sso.setValidateAssertionSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
sso.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
sso.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
sso.setBindingUrl(getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
return sso;
}
private HttpClientConfig parseHttpClientElement(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.HTTP_CLIENT_ELEMENT);
HttpClientConfig config = new HttpClientConfig();
config.setAllowAnyHostname(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
config.setClientKeystore(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_ATTR));
config.setClientKeystorePassword(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_PASSWORD_ATTR));
config.setConnectionPoolSize(getIntegerAttributeValue(startElement, ConfigXmlConstants.CONNECTION_POOL_SIZE_ATTR, 0));
config.setDisableTrustManager(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
config.setProxyUrl(getAttributeValue(startElement, ConfigXmlConstants.PROXY_URL_ATTR));
config.setTruststore(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_ATTR));
config.setTruststorePassword(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_PASSWORD_ATTR));
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent == null)
break;
if (xmlEvent instanceof EndElement) {
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
String endElementName = StaxParserUtil.getEndElementName(endElement);
if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
break;
else
continue;
}
String tag = StaxParserUtil.getStartElementName(startElement);
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
return config;
}
@Override
public boolean supports(QName qname) {
return false;
@@ -48,6 +48,13 @@ public class SPXmlParser extends AbstractParser {
return str;
}
public static int getIntegerAttributeValue(StartElement startElement, String tag, int defaultValue) {
String result = getAttributeValue(startElement, tag);
if (result == null)
return defaultValue;
return Integer.valueOf(result);
}
public static boolean getBooleanAttributeValue(StartElement startElement, String tag, boolean defaultValue) {
String result = getAttributeValue(startElement, tag);
if (result == null)
@@ -0,0 +1,101 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.descriptor.parsers;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.processing.core.util.NamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Goes through the given XML file and extracts names, certificates and keys from the KeyInfo elements.
* @author hmlnarik
*/
public class SamlDescriptorIDPKeysExtractor {
private static final NamespaceContext NS_CONTEXT = new NamespaceContext();
static {
NS_CONTEXT.addNsUriPair("m", JBossSAMLURIConstants.METADATA_NSURI.get());
NS_CONTEXT.addNsUriPair("dsig", JBossSAMLURIConstants.XMLDSIG_NSURI.get());
}
private final KeyInfoFactory kif = KeyInfoFactory.getInstance();
private final XPathFactory xPathfactory = XPathFactory.newInstance();
private final XPath xpath = xPathfactory.newXPath();
{
xpath.setNamespaceContext(NS_CONTEXT);
}
public MultivaluedHashMap<String, KeyInfo> parse(InputStream stream) throws ParsingException {
MultivaluedHashMap<String, KeyInfo> res = new MultivaluedHashMap<>();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(stream);
XPathExpression expr = xpath.compile("/m:EntitiesDescriptor/m:EntityDescriptor/m:IDPSSODescriptor/m:KeyDescriptor");
NodeList keyDescriptors = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < keyDescriptors.getLength(); i ++) {
Node keyDescriptor = keyDescriptors.item(i);
Element keyDescriptorEl = (Element) keyDescriptor;
KeyInfo ki = processKeyDescriptor(keyDescriptorEl);
if (ki != null) {
String use = keyDescriptorEl.getAttribute(JBossSAMLConstants.USE.get());
res.add(use, ki);
}
}
} catch (SAXException | IOException | ParserConfigurationException | MarshalException | XPathExpressionException e) {
throw new ParsingException("Error parsing SAML descriptor", e);
}
return res;
}
private KeyInfo processKeyDescriptor(Element keyDescriptor) throws MarshalException {
NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), JBossSAMLConstants.KEY_INFO.get());
if (childNodes.getLength() == 0) {
return null;
}
Node keyInfoNode = childNodes.item(0);
return (keyInfoNode == null) ? null : kif.unmarshalKeyInfo(new DOMStructure(keyInfoNode));
}
}
@@ -64,11 +64,20 @@ import org.w3c.dom.Node;
import java.io.IOException;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.keycloak.dom.saml.v2.SAML2Object;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
import org.w3c.dom.Element;
/**
*
@@ -257,13 +266,44 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
}
private void validateSamlSignature(SAMLDocumentHolder holder, boolean postBinding, String paramKey) throws VerificationException {
KeyLocator signatureValidationKey = deployment.getIDP().getSignatureValidationKeyLocator();
if (postBinding) {
verifyPostBindingSignature(holder.getSamlDocument(), deployment.getIDP().getSignatureValidationKey());
verifyPostBindingSignature(holder.getSamlDocument(), signatureValidationKey);
} else {
verifyRedirectBindingSignature(deployment.getIDP().getSignatureValidationKey(), paramKey);
String keyId = getMessageSigningKeyId(holder.getSamlObject());
verifyRedirectBindingSignature(paramKey, signatureValidationKey, keyId);
}
}
private String getMessageSigningKeyId(SAML2Object doc) {
final ExtensionsType extensions;
if (doc instanceof RequestAbstractType) {
extensions = ((RequestAbstractType) doc).getExtensions();
} else if (doc instanceof StatusResponseType) {
extensions = ((StatusResponseType) doc).getExtensions();
} else {
return null;
}
if (extensions == null) {
return null;
}
for (Object ext : extensions.getAny()) {
if (! (ext instanceof Element)) {
continue;
}
String res = KeycloakKeySamlExtensionGenerator.getMessageSigningKeyIdFromElement((Element) ext);
if (res != null) {
return res;
}
}
return null;
}
private boolean checkStatusCodeValue(StatusCodeType statusCode, String expectedValue){
if(statusCode != null && statusCode.getValue()!=null){
String v = statusCode.getValue().toString();
@@ -473,10 +513,10 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
return false;
}
public void verifyPostBindingSignature(Document document, PublicKey publicKey) throws VerificationException {
public void verifyPostBindingSignature(Document document, KeyLocator keyLocator) throws VerificationException {
SAML2Signature saml2Signature = new SAML2Signature();
try {
if (!saml2Signature.validate(document, publicKey)) {
if (!saml2Signature.validate(document, keyLocator)) {
throw new VerificationException("Invalid signature on document");
}
} catch (ProcessingException e) {
@@ -484,7 +524,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
}
}
public void verifyRedirectBindingSignature(PublicKey publicKey, String paramKey) throws VerificationException {
private void verifyRedirectBindingSignature(String paramKey, KeyLocator keyLocator, String keyId) throws VerificationException {
String request = facade.getRequest().getQueryParamValue(paramKey);
String algorithm = facade.getRequest().getQueryParamValue(GeneralConstants.SAML_SIG_ALG_REQUEST_KEY);
String signature = facade.getRequest().getQueryParamValue(GeneralConstants.SAML_SIGNATURE_REQUEST_KEY);
@@ -511,16 +551,80 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
try {
//byte[] decodedSignature = RedirectBindingUtil.urlBase64Decode(signature);
byte[] decodedSignature = Base64.decode(signature);
byte[] rawQueryBytes = rawQuery.getBytes("UTF-8");
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.getFromXmlMethod(decodedAlgorithm);
Signature validator = signatureAlgorithm.createSignature(); // todo plugin signature alg
validator.initVerify(publicKey);
validator.update(rawQuery.getBytes("UTF-8"));
if (!validator.verify(decodedSignature)) {
if (! validateRedirectBindingSignature(signatureAlgorithm, rawQueryBytes, decodedSignature, keyLocator, keyId)) {
throw new VerificationException("Invalid query param signature");
}
} catch (Exception e) {
throw new VerificationException(e);
}
}
private boolean validateRedirectBindingSignature(SignatureAlgorithm sigAlg, byte[] rawQueryBytes, byte[] decodedSignature, KeyLocator locator, String keyId)
throws KeyManagementException, VerificationException {
try {
Key key;
try {
key = locator.getKey(keyId);
boolean keyLocated = key != null;
if (validateRedirectBindingSignatureForKey(sigAlg, rawQueryBytes, decodedSignature, key)) {
return true;
}
if (keyLocated) {
return false;
}
} catch (KeyManagementException ex) {
}
} catch (SignatureException ex) {
log.debug("Verification failed for key %s: %s", keyId, ex);
log.trace(ex);
}
if (locator instanceof Iterable) {
Iterable<Key> availableKeys = (Iterable<Key>) locator;
log.trace("Trying hard to validate XML signature using all available keys.");
for (Key key : availableKeys) {
try {
if (validateRedirectBindingSignatureForKey(sigAlg, rawQueryBytes, decodedSignature, key)) {
return true;
}
} catch (SignatureException ex) {
log.debug("Verification failed: %s", ex);
}
}
}
return false;
}
private boolean validateRedirectBindingSignatureForKey(SignatureAlgorithm sigAlg, byte[] rawQueryBytes, byte[] decodedSignature, Key key)
throws SignatureException {
if (key == null) {
return false;
}
if (! (key instanceof PublicKey)) {
log.warnf("Unusable key for signature validation: %s", key);
return false;
}
Signature signature = sigAlg.createSignature(); // todo plugin signature alg
try {
signature.initVerify((PublicKey) key);
} catch (InvalidKeyException ex) {
log.warnf(ex, "Unusable key for signature validation: %s", key);
return false;
}
signature.update(rawQueryBytes);
return signature.verify(decodedSignature);
}
}
@@ -82,8 +82,10 @@ public class WebBrowserSsoAuthenticationHandler extends AbstractSamlAuthenticati
if (deployment.getSignatureCanonicalizationMethod() != null)
binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
binding.signatureAlgorithm(deployment.getSignatureAlgorithm())
.signWith(deployment.getSigningKeyPair())
.signWith(null, deployment.getSigningKeyPair())
.signDocument();
// TODO: As part of KEYCLOAK-3810, add KeyID to the SAML document
// <related DocumentBuilder>.addExtension(new KeycloakKeySamlExtensionGenerator(<key ID>));
}
@@ -113,8 +115,10 @@ public class WebBrowserSsoAuthenticationHandler extends AbstractSamlAuthenticati
if (deployment.getSignatureCanonicalizationMethod() != null)
binding.canonicalizationMethod(deployment.getSignatureCanonicalizationMethod());
binding.signatureAlgorithm(deployment.getSignatureAlgorithm());
binding.signWith(deployment.getSigningKeyPair())
binding.signWith(null, deployment.getSigningKeyPair())
.signDocument();
// TODO: As part of KEYCLOAK-3810, add KeyID to the SAML document
// <related DocumentBuilder>.addExtension(new KeycloakKeySamlExtensionGenerator(<key ID>));
}
binding.relayState("logout");
@@ -0,0 +1,175 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.rotation;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyName;
import org.apache.http.client.HttpClient;
import org.jboss.logging.Logger;
import org.keycloak.adapters.cloned.HttpAdapterUtils;
import org.keycloak.adapters.cloned.HttpClientAdapterException;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.processing.api.util.KeyInfoTools;
/**
* This class defines a {@link KeyLocator} that looks up public keys and certificates in IdP's
* SAML descriptor (i.e. http://{host}/auth/realms/{realm}/protocol/saml/descriptor).
*
* Based on {@code JWKPublicKeyLocator}.
*
* @author hmlnarik
*/
public class SamlDescriptorPublicKeyLocator implements KeyLocator, Iterable<PublicKey> {
private static final Logger LOG = Logger.getLogger(SamlDescriptorPublicKeyLocator.class);
/**
* Time between two subsequent requests (in seconds).
*/
private final int minTimeBetweenDescriptorRequests;
/**
* Time to live for cache entries (in seconds).
*/
private final int cacheEntryTtl;
/**
* Target descriptor URL.
*/
private final String descriptorUrl;
private final Map<String, PublicKey> publicKeyCache = new ConcurrentHashMap<>();
private final HttpClient client;
private volatile int lastRequestTime = 0;
public SamlDescriptorPublicKeyLocator(String descriptorUrl, int minTimeBetweenDescriptorRequests, int cacheEntryTtl, HttpClient httpClient) {
this.minTimeBetweenDescriptorRequests = minTimeBetweenDescriptorRequests <= 0
? 20
: minTimeBetweenDescriptorRequests;
this.descriptorUrl = descriptorUrl;
this.cacheEntryTtl = cacheEntryTtl;
this.client = httpClient;
}
@Override
public Key getKey(String kid) throws KeyManagementException {
if (kid == null) {
LOG.debugf("Invalid key id: %s", kid);
return null;
}
LOG.tracef("Requested key id: %s", kid);
int currentTime = Time.currentTime();
PublicKey res;
if (currentTime > this.lastRequestTime + this.cacheEntryTtl) {
LOG.debugf("Performing regular cache cleanup.");
res = refreshCertificateCacheAndGet(kid);
} else {
res = publicKeyCache.get(kid);
if (res == null) {
if (currentTime > this.lastRequestTime + this.minTimeBetweenDescriptorRequests) {
res = refreshCertificateCacheAndGet(kid);
} else {
LOG.debugf("Won't send request to realm SAML descriptor url, timeout not expired. Last request time was %d", lastRequestTime);
}
}
}
return res;
}
@Override
public synchronized void refreshKeyCache() {
LOG.info("Forcing key cache cleanup and refresh.");
this.publicKeyCache.clear();
refreshCertificateCacheAndGet(null);
}
private synchronized PublicKey refreshCertificateCacheAndGet(String kid) {
if (this.descriptorUrl == null) {
return null;
}
this.lastRequestTime = Time.currentTime();
LOG.debugf("Refreshing public key cache from %s", this.descriptorUrl);
List<KeyInfo> signingCerts;
try {
MultivaluedHashMap<String, KeyInfo> certs = HttpAdapterUtils.downloadKeysFromSamlDescriptor(client, this.descriptorUrl);
signingCerts = certs.get(KeyTypes.SIGNING.value());
} catch (HttpClientAdapterException ex) {
LOG.error("Could not refresh certificates from the server", ex);
return null;
}
if (signingCerts == null) {
return null;
}
LOG.debugf("Certificates retrieved from server, filling public key cache");
// Only clear cache after it is certain that the SAML descriptor has been read successfully
this.publicKeyCache.clear();
for (KeyInfo ki : signingCerts) {
KeyName keyName = KeyInfoTools.getKeyName(ki);
X509Certificate x509certificate = KeyInfoTools.getX509Certificate(ki);
if (x509certificate != null && keyName != null) {
LOG.tracef("Registering signing certificate %s", keyName.getName());
this.publicKeyCache.put(keyName.getName(), x509certificate.getPublicKey());
} else {
LOG.tracef("Ignoring certificate %s: %s", keyName, x509certificate);
}
}
return (kid == null ? null : this.publicKeyCache.get(kid));
}
@Override
public String toString() {
return "Keys retrieved from SAML descriptor at " + descriptorUrl;
}
@Override
public Iterator<PublicKey> iterator() {
if (this.publicKeyCache.isEmpty()) {
refreshCertificateCacheAndGet(null);
}
return this.publicKeyCache.values().iterator();
}
}
@@ -0,0 +1,451 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:keycloak:saml:adapter"
targetNamespace="urn:keycloak:saml:adapter"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="keycloak-saml-adapter" type="adapter-type"/>
<xs:complexType name="adapter-type">
<xs:annotation>
<xs:documentation>Keycloak SAML Adapter configuration file.</xs:documentation>
</xs:annotation>
<xs:all>
<xs:element name="SP" maxOccurs="1" minOccurs="0" type="sp-type">
<xs:annotation>
<xs:documentation>Describes SAML service provider configuration.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
</xs:complexType>
<xs:complexType name="sp-type">
<xs:all>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
List of service provider encryption and validation keys.
If the IDP requires that the client application (SP) sign all of its requests and/or if the IDP will encrypt assertions, you must define the keys used to do this. For client signed documents you must define both the private and public key or certificate that will be used to sign documents. For encryption, you only have to define the private key that will be used to decrypt.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PrincipalNameMapping" type="principal-name-mapping-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>When creating a Java Principal object that you obtain from methods like HttpServletRequest.getUserPrincipal(), you can define what name that is returned by the Principal.getName() method.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RoleIdentifiers" type="role-identifiers-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Defines what SAML attributes within the assertion received from the user should be used as role identifiers within the Java EE Security Context for the user.
By default Role attribute values are converted to Java EE roles. Some IDPs send roles via a member or memberOf attribute assertion. You can define one or more Attribute elements to specify which SAML attributes must be converted into roles.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="IDP" type="idp-type" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:documentation>Describes configuration of SAML identity provider for this service provider.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="entityID" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>This is the identifier for this client. The IDP needs this value to determine who the client is that is communicating with it.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="sslPolicy" type="ssl-policy-type" use="optional">
<xs:annotation>
<xs:documentation>SSL policy the adapter will enforce.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="nameIDPolicyFormat" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request a specific NameID Subject format. Fill in this value if you want a specific format. It must be a standard SAML format identifier, i.e. urn:oasis:names:tc:SAML:2.0:nameid-format:transient. By default, no special format is requested.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="logoutPage" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>URL of the logout page.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="forceAuthentication" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request that a user is re-authenticated even if they are already logged in at the IDP. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="isPassive" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request that a user is never asked to authenticate even if they are not logged in at the IDP. Set this to true if you want this. Do not use together with forceAuthentication as they are opposite. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="turnOffChangeSessionIdOnLogin" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>The session id is changed by default on a successful login on some platforms to plug a security attack vector. Change this to true to disable this. It is recommended you do not turn it off. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="keys-type">
<xs:sequence>
<xs:element name="Key" type="key-type" minOccurs="1" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>Describes a single key used for signing or encryption.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="key-type">
<xs:all>
<xs:element name="KeyStore" maxOccurs="1" minOccurs="0" type="key-store-type">
<xs:annotation>
<xs:documentation>Java keystore to load keys and certificates from.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PrivateKeyPem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Private key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PublicKeyPem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Public key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="CertificatePem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Certificate key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="signing" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Flag defining whether the key should be used for signing.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="encryption" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Flag defining whether the key should be used for encryption</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="key-store-type">
<xs:all>
<xs:element name="PrivateKey" maxOccurs="1" minOccurs="0" type="private-key-type">
<xs:annotation>
<xs:documentation>Private key declaration</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Certificate" type="certificate-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Certificate declaration</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="file" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>File path to the key store.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="resource" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>WAR resource path to the key store. This is a path used in method call to ServletContext.getResourceAsStream().</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>The password of the key store.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="private-key-type">
<xs:attribute name="alias" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Alias that points to the key or cert within the keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Keystores require an additional password to access private keys. In the PrivateKey element you must define this password within a password attribute.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="certificate-type">
<xs:attribute name="alias" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Alias that points to the key or cert within the keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="principal-name-mapping-type">
<xs:attribute name="policy" type="principal-name-mapping-policy-type" use="required">
<xs:annotation>
<xs:documentation>Policy used to populate value of Java Principal object obtained from methods like HttpServletRequest.getUserPrincipal().</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="attribute" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Name of the SAML assertion attribute to use within.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:simpleType name="principal-name-mapping-policy-type">
<xs:restriction base="xs:string">
<xs:enumeration value="FROM_NAME_ID">
<xs:annotation>
<xs:documentation>This policy just uses whatever the SAML subject value is. This is the default setting</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="FROM_ATTRIBUTE">
<xs:annotation>
<xs:documentation>This will pull the value from one of the attributes declared in the SAML assertion received from the server. You'll need to specify the name of the SAML assertion attribute to use within the attribute XML attribute.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ssl-policy-type">
<xs:restriction base="xs:string">
<xs:enumeration value="ALL">
<xs:annotation>
<xs:documentation>All requests must come in via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="EXTERNAL">
<xs:annotation>
<xs:documentation>Only non-private IP addresses must come over the wire via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NONE">
<xs:annotation>
<xs:documentation>no requests are required to come over via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="signature-algorithm-type">
<xs:restriction base="xs:string">
<xs:enumeration value="RSA_SHA1"/>
<xs:enumeration value="RSA_SHA256"/>
<xs:enumeration value="RSA_SHA512"/>
<xs:enumeration value="DSA_SHA1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="binding-type">
<xs:restriction base="xs:string">
<xs:enumeration value="POST"/>
<xs:enumeration value="REDIRECT"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="role-identifiers-type">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Attribute" maxOccurs="unbounded" minOccurs="0" type="attribute-type">
<xs:annotation>
<xs:documentation>Specifies SAML attribute to be converted into roles.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:complexType name="attribute-type">
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Specifies name of the SAML attribute to be converted into roles.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="idp-type">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="SingleSignOnService" maxOccurs="1" minOccurs="1" type="sign-on-type">
<xs:annotation>
<xs:documentation>Configuration of the login SAML endpoint of the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SingleLogoutService" type="logout-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Configuration of the logout SAML endpoint of the IDP</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>The Keys sub element of IDP is only used to define the certificate or public key to use to verify documents signed by the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="HttpClient" type="http-client-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Configuration of HTTP client used for automatic obtaining of certificates containing public keys for IDP signature verification via SAML descriptor of the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="entityID" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>issuer ID of the IDP.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signaturesRequired" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>If set to true, the client adapter will sign every document it sends to the IDP. Also, the client will expect that the IDP will be signing any documents sent to it. This switch sets the default for all request and response types.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signatureAlgorithm" type="signature-algorithm-type" use="optional">
<xs:annotation>
<xs:documentation>Signature algorithm that the IDP expects signed documents to use. Defaults to RSA_SHA256</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the signature canonicalization method that the IDP expects signed documents to use. The default value is http://www.w3.org/2001/10/xml-exc-c14n# and should be good for most IDPs.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="encryption" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="sign-on-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign authn requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect the IDP to sign the assertion response document sent back from an auhtn request? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect the IDP to sign the individual assertions sent back from an auhtn request? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="requestBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>SAML binding type used for communicating with the IDP. The default value is POST, but you can set it to REDIRECT as well.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="responseBinding" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>SAML allows the client to request what binding type it wants authn responses to use. The default is that the client will not request a specific binding type for responses.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="bindingUrl" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>This is the URL for the IDP login service that the client will send requests to.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="logout-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign authn requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signResponse" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign logout responses it sends to the IDP requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect signed logout request documents from the IDP? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect signed logout response documents from the IDP? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="requestBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>This is the SAML binding type used for communicating SAML requests to the IDP. The default value is POST.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="responseBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>This is the SAML binding type used for communicating SAML responses to the IDP. The default value is POST.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="postBindingUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the URL for the IDP's logout service when using the POST binding. This setting is REQUIRED if using the POST binding.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="redirectBindingUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the URL for the IDP's logout service when using the REDIRECT binding. This setting is REQUIRED if using the REDIRECT binding.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="http-client-type">
<xs:attribute name="allowAnyHostname" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>If the the IDP server requires HTTPS and this config option is set to true the IDP's certificate
is validated via the truststore, but host name validation is not done. This setting should only be used during
development and never in production as it will partly disable verification of SSL certificates.
This seting may be useful in test environments. The default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="clientKeystore" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the file path to a keystore file. This keystore contains client certificate
for two-way SSL when the adapter makes HTTPS requests to the IDP server.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="clientKeystorePassword" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Password for the client keystore and for the client's key.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="connectionPoolSize" type="xs:int" use="optional" default="10">
<xs:annotation>
<xs:documentation>Defines number of pooled connections.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="disableTrustManager" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>If the the IDP server requires HTTPS and this config option is set to true you do not have to specify a truststore.
This setting should only be used during development and never in production as it will disable verification of SSL certificates.
The default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="proxyUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>URL to HTTP proxy to use for HTTP connections.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="truststore" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>The value is the file path to a keystore file. If you prefix the path with classpath:,
then the truststore will be obtained from the deployment's classpath instead. Used for outgoing
HTTPS communications to the IDP server. Client making HTTPS requests need
a way to verify the host of the server they are talking to. This is what the trustore does.
The keystore contains one or more trusted host certificates or certificate authorities.
You can create this truststore by extracting the public certificate of the IDP's SSL keystore.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="truststorePassword" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Password for the truststore keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,82 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.keycloak.adapters.cloned;
import java.io.InputStream;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyName;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;
import static org.junit.Assert.*;
import org.keycloak.adapters.saml.config.parsers.ConfigXmlConstants;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.saml.common.exceptions.ParsingException;
/**
*
* @author hmlnarik
*/
public class HttpAdapterUtilsTest {
private <T> T getContent(List<Object> objects, Class<T> clazz) {
for (Object o : objects) {
if (clazz.isInstance(o)) {
return (T) o;
}
}
return null;
}
@Test
public void testExtractKeysFromSamlDescriptor() throws ParsingException {
InputStream xmlStream = HttpAdapterUtilsTest.class.getResourceAsStream("saml-descriptor-valid.xml");
MultivaluedHashMap<String, KeyInfo> res = HttpAdapterUtils.extractKeysFromSamlDescriptor(xmlStream);
assertThat(res, notNullValue());
assertThat(res.keySet(), hasItems(KeyTypes.SIGNING.value()));
assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR), notNullValue());
assertThat(res.get(ConfigXmlConstants.SIGNING_ATTR).size(), equalTo(2));
KeyInfo ki;
KeyName keyName;
X509Data x509data;
X509Certificate x509certificate;
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(0);
assertThat(ki.getContent().size(), equalTo(2));
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
keyName = getContent(ki.getContent(), KeyName.class);
assertThat(keyName.getName(), equalTo("rJkJlvowmv1Id74GznieaAC5jU5QQp_ILzuG-GsweTI"));
x509data = getContent(ki.getContent(), X509Data.class);
assertThat(x509data, notNullValue());
x509certificate = getContent(x509data.getContent(), X509Certificate.class);
assertThat(x509certificate, notNullValue());
assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(1);
assertThat(ki.getContent().size(), equalTo(2));
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(X509Data.class)));
assertThat((List<Object>) ki.getContent(), hasItem(instanceOf(KeyName.class)));
keyName = getContent(ki.getContent(), KeyName.class);
assertThat(keyName.getName(), equalTo("BzYc4GwL8HVrAhNyNdp-lTah2DvU9jU03kby9Ynohr4"));
x509data = getContent(ki.getContent(), X509Data.class);
assertThat(x509data, notNullValue());
x509certificate = getContent(x509data.getContent(), X509Certificate.class);
assertThat(x509certificate, notNullValue());
assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
}
}
@@ -0,0 +1,180 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.config.parsers;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.junit.Test;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.util.StaxParserUtil;
import java.io.InputStream;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.keycloak.saml.common.exceptions.ParsingException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakSamlAdapterXMLParserTest {
private static final String CURRENT_XSD_LOCATION = "/schema/keycloak_saml_adapter_1_7.xsd";
@Rule
public ExpectedException expectedException = ExpectedException.none();
private void testValidationValid(String fileName) throws Exception {
InputStream schema = getClass().getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream is = getClass().getResourceAsStream(fileName);
assertNotNull(is);
assertNotNull(schema);
StaxParserUtil.validate(is, schema);
}
@Test
public void testValidationSimpleFile() throws Exception {
testValidationValid("keycloak-saml.xml");
}
@Test
public void testValidationMultipleKeys() throws Exception {
testValidationValid("keycloak-saml-multiple-signing-keys.xml");
}
@Test
public void testValidationWithHttpClient() throws Exception {
testValidationValid("keycloak-saml-wth-http-client-settings.xml");
}
@Test
public void testValidationKeyInvalid() throws Exception {
InputStream schemaIs = KeycloakSamlAdapterXMLParser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
assertNotNull(is);
assertNotNull(schemaIs);
expectedException.expect(ParsingException.class);
StaxParserUtil.validate(is, schemaIs);
}
@Test
public void testXmlParser() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
assertEquals("sp", sp.getEntityID());
assertEquals("EXTERNAL", sp.getSslPolicy());
assertEquals("format", sp.getNameIDPolicyFormat());
assertTrue(sp.isForceAuthentication());
assertTrue(sp.isIsPassive());
assertEquals(2, sp.getKeys().size());
Key signing = sp.getKeys().get(0);
assertTrue(signing.isSigning());
Key.KeyStoreConfig keystore = signing.getKeystore();
assertNotNull(keystore);
assertEquals("file", keystore.getFile());
assertEquals("cp", keystore.getResource());
assertEquals("pw", keystore.getPassword());
assertEquals("private alias", keystore.getPrivateKeyAlias());
assertEquals("private pw", keystore.getPrivateKeyPassword());
assertEquals("cert alias", keystore.getCertificateAlias());
Key encryption = sp.getKeys().get(1);
assertTrue(encryption.isEncryption());
assertEquals("private pem", encryption.getPrivateKeyPem());
assertEquals("public pem", encryption.getPublicKeyPem());
assertEquals("FROM_ATTRIBUTE", sp.getPrincipalNameMapping().getPolicy());
assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName());
assertTrue(sp.getRoleAttributes().size() == 1);
assertTrue(sp.getRoleAttributes().contains("member"));
IDP idp = sp.getIdp();
assertEquals("idp", idp.getEntityID());
assertEquals("RSA_SHA256", idp.getSignatureAlgorithm());
assertEquals("canon", idp.getSignatureCanonicalizationMethod());
assertTrue(idp.getSingleSignOnService().isSignRequest());
assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
assertEquals("POST", idp.getSingleSignOnService().getRequestBinding());
assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
assertTrue(idp.getSingleLogoutService().isSignRequest());
assertTrue(idp.getSingleLogoutService().isSignResponse());
assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
assertEquals("REDIRECT", idp.getSingleLogoutService().getRequestBinding());
assertEquals("POST", idp.getSingleLogoutService().getResponseBinding());
assertEquals("posturl", idp.getSingleLogoutService().getPostBindingUrl());
assertEquals("redirecturl", idp.getSingleLogoutService().getRedirectBindingUrl());
assertTrue(idp.getKeys().size() == 1);
assertTrue(idp.getKeys().get(0).isSigning());
assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
}
@Test
public void testXmlParserMultipleSigningKeys() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml-multiple-signing-keys.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertTrue(idp.getKeys().size() == 4);
for (int i = 0; i < 4; i ++) {
Key key = idp.getKeys().get(i);
assertTrue(key.isSigning());
assertEquals("cert pem " + i, idp.getKeys().get(i).getCertificatePem());
}
}
@Test
public void testXmlParserHttpClientSettings() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml-wth-http-client-settings.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter) parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertThat(idp.getHttpClientConfig(), notNullValue());
assertThat(idp.getHttpClientConfig().getClientKeystore(), is("ks"));
assertThat(idp.getHttpClientConfig().getClientKeystorePassword(), is("ks-pwd"));
assertThat(idp.getHttpClientConfig().getProxyUrl(), is("pu"));
assertThat(idp.getHttpClientConfig().getTruststore(), is("ts"));
assertThat(idp.getHttpClientConfig().getTruststorePassword(), is("tsp"));
assertThat(idp.getHttpClientConfig().getConnectionPoolSize(), is(42));
assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
}
}
@@ -1,133 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.test.adapters.saml;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.adapters.saml.config.parsers.KeycloakSamlAdapterXMLParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class XmlParserTest {
@Test
public void testValidation() throws Exception {
{
InputStream schema = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
Assert.assertNotNull(is);
Assert.assertNotNull(schema);
StaxParserUtil.validate(is, schema);
}
{
InputStream sch = KeycloakSamlAdapterXMLParser.class.getResourceAsStream("/schema/keycloak_saml_adapter_1_6.xsd");
InputStream doc = getClass().getResourceAsStream("/keycloak-saml2.xml");
Assert.assertNotNull(doc);
Assert.assertNotNull(sch);
try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(sch));
Validator validator = schema.newValidator();
StreamSource source = new StreamSource(doc);
source.setSystemId("/keycloak-saml2.xml");
validator.validate(source);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Test
public void testXmlParser() throws Exception {
InputStream is = getClass().getResourceAsStream("/keycloak-saml.xml");
Assert.assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
Assert.assertNotNull(config);
Assert.assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
Assert.assertEquals("sp", sp.getEntityID());
Assert.assertEquals("ssl", sp.getSslPolicy());
Assert.assertEquals("format", sp.getNameIDPolicyFormat());
Assert.assertTrue(sp.isForceAuthentication());
Assert.assertTrue(sp.isIsPassive());
Assert.assertEquals(2, sp.getKeys().size());
Key signing = sp.getKeys().get(0);
Assert.assertTrue(signing.isSigning());
Key.KeyStoreConfig keystore = signing.getKeystore();
Assert.assertNotNull(keystore);
Assert.assertEquals("file", keystore.getFile());
Assert.assertEquals("cp", keystore.getResource());
Assert.assertEquals("pw", keystore.getPassword());
Assert.assertEquals("private alias", keystore.getPrivateKeyAlias());
Assert.assertEquals("private pw", keystore.getPrivateKeyPassword());
Assert.assertEquals("cert alias", keystore.getCertificateAlias());
Key encryption = sp.getKeys().get(1);
Assert.assertTrue(encryption.isEncryption());
Assert.assertEquals("private pem", encryption.getPrivateKeyPem());
Assert.assertEquals("public pem", encryption.getPublicKeyPem());
Assert.assertEquals("policy", sp.getPrincipalNameMapping().getPolicy());
Assert.assertEquals("attribute", sp.getPrincipalNameMapping().getAttributeName());
Assert.assertTrue(sp.getRoleAttributes().size() == 1);
Assert.assertTrue(sp.getRoleAttributes().contains("member"));
IDP idp = sp.getIdp();
Assert.assertEquals("idp", idp.getEntityID());
Assert.assertEquals("RSA", idp.getSignatureAlgorithm());
Assert.assertEquals("canon", idp.getSignatureCanonicalizationMethod());
Assert.assertTrue(idp.getSingleSignOnService().isSignRequest());
Assert.assertTrue(idp.getSingleSignOnService().isValidateResponseSignature());
Assert.assertEquals("post", idp.getSingleSignOnService().getRequestBinding());
Assert.assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
Assert.assertTrue(idp.getSingleLogoutService().isSignRequest());
Assert.assertTrue(idp.getSingleLogoutService().isSignResponse());
Assert.assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
Assert.assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
Assert.assertEquals("redirect", idp.getSingleLogoutService().getRequestBinding());
Assert.assertEquals("post", idp.getSingleLogoutService().getResponseBinding());
Assert.assertEquals("posturl", idp.getSingleLogoutService().getPostBindingUrl());
Assert.assertEquals("redirecturl", idp.getSingleLogoutService().getRedirectBindingUrl());
Assert.assertTrue(idp.getKeys().size() == 1);
Assert.assertTrue(idp.getKeys().get(0).isSigning());
Assert.assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
}
}
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Name="urn:keycloak">
<EntityDescriptor entityID="http://localhost:8081/auth/realms/master">
<IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<dsig:KeyInfo>
<dsig:KeyName>rJkJlvowmv1Id74GznieaAC5jU5QQp_ILzuG-GsweTI</dsig:KeyName>
<dsig:X509Data>
<dsig:X509Certificate>
MIICmzCCAYMCBgFX/9ccIDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTYxMDI2MDcxMjUwWhcNMjYxMDI2MDgxNDMwWjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPjDrM890OoFWLIU5xNT+v8B8EkpOGY1y/9Yi/yQd95uG/p5LaywiPsw+lPy4tSn1pH/2SxNDST2zynKPDd1lYDev43m0sC2FfD2H73q3udQRqSOxW1e8FrTrGDIHxb82UNrCPlu+fH+xYSkigrkOvLvPigTwSIcu8vgs0lk9FqJ81ty3Wj2e9lS7JJGAJ3pC7rp39VLdJSKbfyj/v2RYBeG5Pscncl8cjUOHUq5u19hThjkU2jOBzgIK2JS0bNmzSfH1eBTZMoCQBI1UJ1IbA8tqjQwpOXc+JkPBRU8T/JUQoQlSR6DTcPFvDgH2oGZYFHFfUontZqtz8jrIt2pxBAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK5VgQp1x1FKgabFI6W/iGuy9ZCRoAixOOEGGkDps6dOEFgTQKTy5D/FZts9KuNxhhiD+NvS0d5BKYa5ITPLVPnGucgYkZhz+/+GhxmbjeQr0eJPaY7ZgLfH3tPA6tfdIkA0iE1En1sKEwt6R6DZjh9jtP9laoUoddTvYaFLJpZ2u1Ik94q6ZqX0fS/RKchaBHjhg6MtqCcHt07CBKHh8XNmKPXVSJC/p0MjyXv+qLaNNqyaAvAw6P6DX1hNjzrdkuaaHGXhu6kkezZUVlDWAm9cd1ppqalSK6ggy7yMW1NWTd/NYOPsFU2TS8DDPzRo14s1Qvw4v+TY6yT0NURJPQA=
</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
</KeyDescriptor>
<KeyDescriptor use="signing">
<dsig:KeyInfo>
<dsig:KeyName>BzYc4GwL8HVrAhNyNdp-lTah2DvU9jU03kby9Ynohr4</dsig:KeyName>
<dsig:X509Data>
<dsig:X509Certificate>
MIICmzCCAYMCBgFX/9eK7TANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTYxMDI2MDcxMzE4WhcNMjYxMDI2MDgxNDU4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCDLT+40/BWzWPSVmpaSaZRs5lBMQ9VP9TCoXkby4PHqxIWRecTPM8fcNkPNPE/tiR2tUIpMXPDzgXNFA/EMoB3V1OEVXPecjKtiZczdR6pi75CBx7PJ2fSXg6xpjhZmHu0k7x591GZdP8Iiu2E6b9QA2p5VXgNgfuP07XzgabnSvIrLG60Imus3u6C2qA/QEuY7EYQWrFooriYLW6B8s3xU8R1a92SLMT8JsfMWXi+1CzAhIbVvdwUwkhVDDhAU6pUek88QQgxodd3FAMksoijCGFN1yrCkovlFhKb3j9AC6Icd9eeJuwYddN/nMeMGEDOeCcAGBACiaUisjUvZDw1AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHAHbBI0CRfdw5ZHxHAjgSQvSj41c/4cfwln4Q7X3I5lMBbW3tcgond6Ku9eU46FzG5VpgXIgvEf4u0O9jUnxLlO50+t2SHwQ1RwHdBWQngVSZCRzscq3KrSzx1hx88qLyqcPrr3QtR92fYipDjENxttT/qJtDMrXlwLZEITlHDoneX319USYB9C4zlrCIsQ5XxQTTyCx886Pz15DSVSRxVp61HGk6ROsX/DG5/xwInlzgMZ0r3JWnAjtAaXqUrcwH9FXxco+xkiqKW79bGhWGQI9sXXvQSSNAaENMIUhxtd9uOi1l5e0EkKHE2fHlYyfdUDnFJWwSMXd/NM+hVI4Lw=
</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
</KeyDescriptor>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
<NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
</NameIDFormat>
<NameIDFormat>
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/auth/realms/master/protocol/saml"/>
</IDPSSODescriptor>
</EntityDescriptor>
</EntitiesDescriptor>
@@ -0,0 +1,83 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_7.xsd">
<SP entityID="sp"
sslPolicy="ALL"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<KeyStore file="file" resource="cp" password="pw">
<PrivateKey alias="private alias" password="private pw"/>
<Certificate alias="cert alias"/>
</KeyStore>
</Key>
<Key encryption="true">
<PrivateKeyPem>
private pem
</PrivateKeyPem>
<PublicKeyPem>
public pem
</PublicKeyPem>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp"
signatureAlgorithm="RSA_SHA512"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="bindingurl"
/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="REDIRECT"
responseBinding="POST"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<CertificatePem>cert pem 0</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 1</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 2</CertificatePem>
</Key>
<Key signing="true">
<CertificatePem>cert pem 3</CertificatePem>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
@@ -0,0 +1,83 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_7.xsd">
<SP entityID="sp"
sslPolicy="ALL"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<KeyStore file="file" resource="cp" password="pw">
<PrivateKey alias="private alias" password="private pw"/>
<Certificate alias="cert alias"/>
</KeyStore>
</Key>
<Key encryption="true">
<PrivateKeyPem>
private pem
</PrivateKeyPem>
<PublicKeyPem>
public pem
</PublicKeyPem>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp"
signatureAlgorithm="RSA_SHA512"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="url"
/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="REDIRECT"
responseBinding="POST"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<CertificatePem>
cert pem
</CertificatePem>
</Key>
</Keys>
<HttpClient allowAnyHostname="true"
clientKeystore="ks" clientKeystorePassword="ks-pwd"
connectionPoolSize="42"
disableTrustManager="true"
proxyUrl="pu"
truststore="ts" truststorePassword="tsp"
/>
</IDP>
</SP>
</keycloak-saml-adapter>
@@ -15,14 +15,16 @@
~ limitations under the License.
-->
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter">
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_7.xsd">
<SP entityID="sp"
sslPolicy="ssl"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<Key signing="true">
<KeyStore file="file" resource="cp" password="pw">
<PrivateKey alias="private alias" password="private pw"/>
<Certificate alias="cert alias"/>
@@ -37,18 +39,18 @@
</PublicKeyPem>
</Key>
</Keys>
<PrincipalNameMapping policy="policy" attribute="attribute"/>
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp"
signatureAlgorithm="RSA"
signatureAlgorithm="RSA_SHA256"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="post"
requestBinding="POST"
bindingUrl="url"
/>
@@ -57,8 +59,8 @@
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="redirect"
responseBinding="post"
requestBinding="REDIRECT"
responseBinding="POST"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Jetty Integration</name>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -153,14 +153,14 @@ public class CatalinaSamlSessionStore implements SamlSessionStore {
}
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
if (samlSession.getPrincipal().getName().equals(principal.getName()))
// in clustered environment in JBossWeb, principal is not serialized or saved
if (principal == null) {
principal = principalFactory.createPrincipal(request.getContext().getRealm(), samlSession.getPrincipal(), samlSession.getRoles());
session.setPrincipal(principal);
session.setAuthType("KEYCLOAK-SAML");
} else {
}
else if (samlSession.getPrincipal().getName().equals(principal.getName())){
if (!principal.getUserPrincipal().getName().equals(samlSession.getPrincipal().getName())) {
throw new RuntimeException("Unknown State");
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Wildfly Integration</name>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.3.0-SNAPSHOT</version>
<version>2.4.0.CR1-SNAPSHOT</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
Loaded 100 of 1368 files, more files were not shown because too many files have changed in this diff. Show more