Compare commits

...
370 Commits
Author SHA1 Message Date
keycloak-bot aa4b34d1aa Set version to 4.0.0.Beta1 2018-03-22 15:13:47 +00:00
stianst ffd084f414 Removed authz from examples-dist 2018-03-22 14:57:15 +01:00
Hynek Mlnarik bb3c76a9d9 KEYCLOAK-6929 Externalizers for AuthenticationSessionEntity 2018-03-21 12:46:50 +01:00
June Zhang ca15db81bb KEYCLOAK-6262 Incorporate new visual design from PatternFly (#4983)
* KEYCLOAK-6262 Incorporate new visual design from PatternFly

Update the username or email

Fix narrow/wide in template.ftl

minor style update

Add the Realm HTML name and image

Config OTP and Update Password
Not display the locale selector if there is less than 1 locale.

Fix margins/paddings on config otp screens

Fix title

Upgraded to PatternFly 3.41.6

Added RCUE and updated RH-SSO login theme

Refine the RCUE padding issue

Fix tests

Fix Keycloak background

Fix

* fix the overflowing issue

* Fix Console UI Tests to reflect the new login page

* Fix the different style of the IdP buttons
Fix the IE placeholder issue - add label

* Removed placeholder on login and reset pass. Fixed Keycloak background on wide screens.

* fixed the stackoverflow issues
fixed the width in the tablets
2018-03-21 10:47:33 +01:00
Pedro Igor 66507cbf91 Merge pull request #5081 from sguilhen/KC6543
[KEYCLOAK-6543] Remove the authz examples from the Keycloak codebase.
2018-03-20 09:09:04 -03:00
Jérôme Blanchard f11c24e359 [KEYCLOAK-6147] Include Nonce in OIDC authentication 2018-03-20 10:51:44 +01:00
Alex Szczuczko 3ade41a76d KEYCLOAK-6299 Upstream keycloak-javadocs-pom into the product profile of keycloak-api-docs-dist
A product profile has been added to keycloak-api-docs-dist, to replace the
downstream product javadocs POM. I've merged in any misc. changes from that
pom, but I've kept the upstream zip layout:

```
index.html
rest-api/index.html
javadocs/index.html
javadocs/index-all.html
javadocs/*
```

instead of the current product deliverable layout of:

```
META-INF/*
index.html
index-all.html
*
```

The community layout includes the rest-api that's distributed as a separate
product deliverable in 7.2.0. I've kept this layout for better artifact
consistency, but it could easily be changed to keep the product artifacts
consistent for the next product minor version.
2018-03-20 04:41:31 +01:00
Stefan Guilhen 35b9fe043c [KEYCLOAK-6543] Remove the authz examples from the Keycloak codebase. 2018-03-19 17:00:02 -03:00
Áron Bustya 82ba2b1b0d remove changes from standard OIDC client registration, move constants 2018-03-19 19:31:22 +01:00
Áron Bustya 57f57f5c75 set request object mandatory for client, restrict delivery mode
handle new attribute in client representation


add to UI
2018-03-19 19:31:22 +01:00
Pedro Igor 917ba90f2c Merge pull request #5077 from pedroigor/KEYCLOAK-6628
[KEYCLOAK-6628] - Expose methods to query roles, groups, and attributes of users in Evaluation API
2018-03-19 08:54:12 -03:00
mhajas 3cf104580e KEYCLOAK-6642 Stabilize Cluster tests 2018-03-19 07:45:35 +01:00
Pedro Igor 7cfe6addf0 Merge pull request #5078 from sguilhen/KC5886
[KEYCLOAK-5886] Improvements to Photoz example
2018-03-16 10:30:22 -03:00
Alex Szczuczko e4781b8aa3 KEYCLOAK-6828 Drop jcenter repository from services/pom.xml
swagger2markup-maven-plugin depends transitively on markdown_to_asciidoc, which
is inexplicably not in Central. This causes issues during productisation, as
it's reasonably assumed that all third party artifacts will be in Central.

Stian has already asked the community project to get their artifacts in Central
( bodiam/markdown-to-asciidoc#26 ), and they haven't done anything in almost a
year. So, I've added the artifacts under my own namespace, and changed the pom
to use those instead. The artifacts are unchanged from the ones on jcenter,
except the pom was expanded slightly to meet the minimum requirements of
Central.

I'm making this change now, as I hit the problem when trying to set up
continuous productization builds from master.
2018-03-16 08:36:04 +01:00
Johannes Knutsen 9de8e79577 KEYCLOAK-6824: Remove negation of isEmpty list check 2018-03-15 18:43:22 +01:00
mhajas 3826f6fae2 KEYCLOAK-3161 KEYCLOAK-3165 Migrate SAML tests from old testsuite to integration-arquillian 2018-03-15 18:15:44 +01:00
pedroigor 711bf244ed [KEYCLOAK-6628] - Expose methods to query roles, groups, and attributes of users in Evaluation API 2018-03-15 14:02:15 -03:00
Stefan Guilhen 99d0811412 [KEYCLOAK-5886] Improvements to Photoz example
- Fixed location of the authz json file in the README
 - Added links to allow easy navigation back to the main page
 - requestEntitlements link now properly display the RPT
2018-03-15 09:56:12 -03:00
sebastienblanc ee2d28d589 KEYCLOAK-6775 : fix french typos 2018-03-14 21:13:46 +01:00
Inki Hwang 22e32117e0 [KEYCLOAK-6789] show client id when client name is empty 2018-03-14 15:20:20 +01:00
Douglas Palmer fed1b62c5d [KEYCLOAK-6301] Remove service account when it is disabled from the client 2018-03-14 15:09:42 +01:00
Takashi Norimatsu 5b1e65c23e KEYCLOAK-6700 Financial API Read and Write API Security Profile : state
hash value (s_hash) to protect state parameter
2018-03-13 16:40:34 +01:00
Takashi Norimatsu e72756d01a KEYCLOAK-6700 Financial API Read and Write API Security Profile : state hash value (s_hash) to protect state parameter 2018-03-13 16:40:34 +01:00
Pedro Igor 871ecf83fb Merge pull request #5071 from vramik/KEYCLOAK-6644-stabilize-PhotozExampleAdapterTest
KEYCLOAK-6644 PhotozExampleAdapterTest is not stable
2018-03-13 09:03:57 -03:00
vmuzikar daaa35bc37 KEYCLOAK-6831 Fix Microsoft Social Login test 2018-03-13 10:19:27 +01:00
vramik 9d10ccef70 KEYCLOAK-6644 PhotozExampleAdapterTest is not stable 2018-03-13 09:53:17 +01:00
Pedro Igor 2aa71d1737 Merge pull request #5051 from pedroigor/KEYCLOAK-6787
[KEYCLOAK-6787] - Wrong validation of resources with same name and different owners
2018-03-12 11:41:49 -03:00
Pedro Igor b9b1102b74 Merge pull request #5004 from pedroigor/KEYCLOAK-6623
[KEYCLOAK-6623] - Policy enforcer gets confused with similar paths ending with wildcards
2018-03-12 09:59:05 -03:00
Pedro Igor f824582aac Merge pull request #5009 from pedroigor/KEYCLOAK-6116
[KEYCLOAK-6116] - Get email attribute from 'subject alternative name' using X509 certificate
2018-03-12 09:58:02 -03:00
pedroigor 199f289ee3 [KEYCLOAK-6623] - Adding test 2018-03-09 16:39:33 -03:00
pedroigor 668b67dcdb [KEYCLOAK-6623] - Policy enforcer gets confused with similar paths ending with wildcards 2018-03-09 16:38:57 -03:00
Hynek Mlnarik 190771ddf1 KEYCLOAK-6783 Add authentication into cross-dc testing 2018-03-09 15:08:55 +01:00
Hynek Mlnarik 05dcc6e3af KEYCLOAK-6783 JDG-auth optimizations 2018-03-09 15:08:55 +01:00
mposolda 6f7200868b Secured RemoteCache availability 2018-03-09 15:08:55 +01:00
pedroigor 62b70b561e [KEYCLOAK-6116] - Removing references to phantomjs.cli.args 2018-03-09 10:56:35 -03:00
pedroigor 1f13427dee [KEYCLOAK-6116] - Enabling tests for both jboss servers 2018-03-09 10:56:35 -03:00
pedroigor 6aee573e2e [KEYCLOAK-6116] - Tests for X509 Subject Alternative Name Extension 2018-03-09 10:56:35 -03:00
pedroigor c5c285abc3 [KEYCLOAK-6116] - Adding a OpenSSL CA Authority for testing 2018-03-09 10:56:35 -03:00
pedroigor 0a4fd79b22 [KEYCLOAK-6116] - Get email attribute from 'subject alternative name' using X509 certificate 2018-03-09 10:56:35 -03:00
Marko Strukelj b29edc7056 Merge pull request #5049 from tkyjovsk/KEYCLOAK-6165
KEYCLOAK-6165 Ability to load performance provisioning and test parameters from a properties file
2018-03-07 15:20:57 +01:00
Marko Strukelj 97aa3f5f36 Merge pull request #5064 from tkyjovsk/KEYCLOAK-6683
KEYCLOAK-6683 Ability to archive logs of provisioned docker instances
2018-03-07 15:16:16 +01:00
vmuzikar d66c33a8b9 KEYCLOAK-6793 Support custom Chrome binary in Arquillian testsuite 2018-03-07 10:38:12 +01:00
Tomas Kyjovsky 63383f8032 KEYCLOAK-6683 Ability to archive logs of provisioned docker instances 2018-03-06 23:49:08 +01:00
Pedro Igor a63a01c9ea Merge pull request #5060 from vmuzikar/fix-authz-KEYCLOAK-6802
KEYCLOAK-6802 Fix ScopePermissionManagement Console UI test
2018-03-06 15:47:12 -03:00
Tomas Kyjovsky dabf4e8bbd KEYCLOAK-6165 Ability to load performance provisioning and test parameters from a properties file 2018-03-06 19:19:24 +01:00
Marko Strukelj 35ffdb4745 Merge pull request #5030 from tkyjovsk/KEYCLOAK-6512
Keycloak 6512 Open workload injection model
2018-03-06 15:39:37 +01:00
Tomas Kyjovsky b0d63980e3 KEYCLOAK-6512 Open workload injection model + LogProcessor fixes 2018-03-06 13:20:20 +01:00
wyvie c27ffbda8b [KEYCLOAK-6643] server version now retreived from server info web page 2018-03-06 10:49:09 +01:00
vmuzikar 502fc62967 KEYCLOAK-6797 Fix Social Login test 2018-03-06 10:19:10 +01:00
Bill Burke c06ac70633 Merge pull request #5059 from patriot1burke/keycloak-6026
KEYCLOAK-6026
2018-03-05 16:54:45 -05:00
vmuzikar 414d51b02b KEYCLOAK-6802 Fix ScopePermissionManagement Console UI test 2018-03-05 18:19:54 +01:00
Bill Burke 4b6b45cf43 KEYCLOAK-6026 2018-03-05 11:57:05 -05:00
Bill Burke d90affa47d Merge remote-tracking branch 'upstream/master' into keycloak-6026 2018-03-02 18:54:10 -05:00
Bill Burke d5a075da30 Merge pull request #5057 from patriot1burke/client-flow-console
KEYCLOAK-6336
2018-03-02 18:52:34 -05:00
Pedro Igor 1b06194455 Merge pull request #5050 from TeliaSoneraNorge/KEYCLOAK-6659
Add pairwise sub support to authorization services
2018-03-02 14:44:28 -03:00
Bill Burke e2bec73011 KEYCLOAK-6336 2018-03-02 12:29:07 -05:00
Bill Burke 07613bcca0 Merge remote-tracking branch 'upstream/master' into client-flow-console 2018-03-02 11:30:19 -05:00
Bill Burke cc24484eaf Merge remote-tracking branch 'upstream/master' 2018-03-02 11:29:13 -05:00
Martin Hardselius 8549bd70b7 Add pairwise sub support to authorization services
Identity token verification will now fetch the user from the session
state instead of relying on the sub provided in the token. Also done in
KeycloakIdentity.

Resolves: KEYCLOAK-6659
2018-03-02 13:08:27 +01:00
vramik 9bd2e70376 KEYCLOAK-6790 Identifier for RESOURCE_SERVER_PERMISSION_TICKET table is too long for Oracle databases 2018-03-02 12:46:19 +01:00
vramik 569f26776e KEYCLOAK-5060 KEYCLOAK-3157 migrated Adapter package from old testsuite 2018-03-02 10:56:26 +01:00
Bill Burke 7f21cdd1f4 KEYCLOAK-6551 2018-03-02 10:41:05 +01:00
Bill Burke 7b5a0c6dcf KEYCLOAK-6551 2018-03-01 21:29:58 -05:00
pedroigor 1e1de85685 [KEYCLOAK-6787] - Wrong validation of resources with same name and different owners 2018-03-01 16:50:05 -03:00
Pedro Igor 9b1275f182 Merge pull request #5021 from pedroigor/KEYCLOAK-6621
[KEYCLOAK-6621] - Removing unnecessary code to process scopes from typed resources
2018-03-01 09:40:02 -03:00
pedroigor cb531056a6 [KEYCLOAK-6621] - Fixing cache and queries of policies with type scope 2018-02-28 16:33:45 -03:00
pedroigor b0200d462d [KEYCLOAK-6621] - Removing unnecessary code to process scopes from typed resources 2018-02-28 16:33:45 -03:00
vmuzikar 028e78f46b KEYCLOAK-6772 Fix SessionsPreloadCrossDCTest 2018-02-28 20:14:50 +01:00
Hynek Mlnarik 9ca7b22cec KEYCLOAK-6777 Fix AccountPageTest 2018-02-28 16:28:48 +01:00
Hynek Mlnarik 1b45ab2601 KEYCLOAK-6773 XML vulnerability test 2018-02-28 15:05:07 +01:00
Bill Burke 215bbaac6c hide tab when no client storage providers 2018-02-28 08:47:13 -05:00
Bill Burke 53f96099fb review fixes 2018-02-28 08:47:13 -05:00
Bill Burke 681256a079 KEYCLOAK-6622 2018-02-28 08:47:13 -05:00
mhajas 2a4663c940 KEYCLOAK-6471 Refactor SAML metadata parsers 2018-02-28 14:08:06 +01:00
Gaétan Collaud 1d88d061e6 French translation for KEYCLOAK-2120
* Added translation for KEYCLOAK-2120
* Removed link in translation since apps are now in a list (and html was escaped)
2018-02-28 08:55:26 +01:00
Gaétan Collaud 123c6dffe0 Improved french translation
In french, the "forgot password" email displays the full link instead of having a message like other languages.

`Lien pour réinitialiser votre mot de passe` = `Link to reset your password`.
2018-02-28 08:55:03 +01:00
Pedro Igor 91bdc4bde2 [KEYCLOAK-3169] - UMA 2.0 (#4368)
* [KEYCLOAK-3169] - UMA 2.0 Support

* [KEYCLOAK-3169] - Changes to account service and more tests

* [KEYCLOAK-3169] - Code cleanup and tests

* [KEYCLOAK-3169] - Changes to account service and tests

* [KEYCLOAK-3169] - Changes to account service and tests

* [KEYCLOAK-3169] - More tests

* [KEYCLOAK-3169] - Changes to adapter configuration

* [KEYCLOAK-3169] - Reviewing UMA specs and more tests

* [KEYCLOAK-3169] - Reviewing UMA specs and more tests

* [KEYCLOAK-3169] - Changes to UMA Grant Type and refactoring

* [KEYCLOAK-3169] - Refresh tokens for RPT responses and tests

* [KEYCLOAK-3169] - Changes to account my resources and policy enforcers

* [KEYCLOAK-3169] - Realm settings flag to enable/disable user-managed access in account mgmt console

* [KEYCLOAK-3169] - More changes to my resource pages in account mgmt console

* [KEYCLOAK-3169] - Need to enable user-managed on realm to run tests

* [KEYCLOAK-3169] - Removing more UMA 1.0 related code

* [KEYCLOAK-3169] - Only submit requests if ticket exists

* [KEYCLOAK-3169] - Returning UMA 401 response when not authenticated

* [KEYCLOAK-3169] - Removing unused code

* [KEYCLOAK-3169] - Removing unused code

* [KEYCLOAK-3169] - 403 response in case ticket is not created

* [KEYCLOAK-3169] - Fixing AbstractPhotozExampleAdapterTest#testClientRoleRepresentingUserConsent

* [KEYCLOAK-3169] - 403 status code only returned for non-bearer clients
2018-02-28 08:53:10 +01:00
Ferdinand Hübner 190ad06f1a KEYCLOAK-6618 Update German translations (#5002)
* KEYCLOAK-6618 Update German translations

Add missing translations for OTP authenticator settings and update
outdated translations for OTP authenticator

Fix minor issue for the username property (plural -> singular)

Add missing translations

* KEYCLOAK-6618: Include review feedback into German translations

* KEYCLOAK-6618: Reword translation for multi-factor authentication and fix minor translation issues

* KEYCLOAK-6618: Update German translation for the login theme

Message bundle keys have been reordered to be in sync with the english
version to improve scanning through the message bundles side-by-side.

The updated German translations from the account theme were applied to
the login theme as well (where applicable).
2018-02-28 05:10:31 +01:00
wyvie f8022a5c2f [KEYCLOAK-6585] hybrid flow: removed token_type and expires_in paramters from oidc auth response 2018-02-27 15:31:12 +01:00
mhajas e52380915b KEYCLOAK-4817 Fix instability 2018-02-27 14:35:52 +01:00
vmuzikar 08bf19d4aa KEYCLOAK-6694 Revamp OpenShift Social Login test 2018-02-27 12:28:42 +01:00
vmuzikar a2cc7bd4b9 KEYCLOAK-6709 Fix OpenShift IdP doesn't fetch user's full name 2018-02-27 12:28:42 +01:00
Marko Strukelj b8637bf1fa Merge pull request #5031 from tkyjovsk/KEYCLOAK-5973
KEYCLOAK-5973 Filtering of Gatling results
2018-02-27 12:00:27 +01:00
Tomas Kyjovsky 417c31bc0b KEYCLOAK-5973 Filtering of Gatling results 2018-02-27 10:33:24 +01:00
Hynek Mlnarik 1f20c03afa KEYCLOAK-6470 Refactor SAML adapter parsers 2018-02-27 09:37:29 +01:00
vmuzikar d70e4740fc KEYCLOAK-6693 Support external truststore in testsuite 2018-02-27 07:45:21 +01:00
Marko Strukelj b1d42381cd Merge pull request #5025 from tkyjovsk/KEYCLOAK-5372
KEYCLOAK-5372 Add warm-up, test-time, ramp-down times
2018-02-26 22:20:50 +01:00
Bill Burke aa089980ce Merge pull request #4942 from mstruk/KEYCLOAK-5807
KEYCLOAK-5807 Intermittent failures in UserStorageTest
2018-02-26 12:14:38 -05:00
wyvie 52acd959e0 [KEYCLOAK-6584] removed not-before-policy parameter from authorization response 2018-02-26 17:41:18 +01:00
Josh Cain 8cf65bc37d add getExecution method to admin resource 2018-02-26 17:00:17 +01:00
Josh Cain 24132c8f5b Return location for execution and flow creation in admin interface. Also allow for retrieval of execution by ID 2018-02-26 17:00:17 +01:00
mhajas fe1c447d9a KEYCLOAK-6546 Run filter test on WebLogic and WebSphere 2018-02-26 15:47:13 +01:00
Hynek Mlnarik bde9210fa3 KEYCLOAK-6692 Fix LogoutTest on Oracle 2018-02-26 15:45:55 +01:00
Václav Muzikář 10e31c397c KEYCLOAK-6592 Fix TokensTest#testButtonDisabledForEmptyAttributes in FF (#4996) 2018-02-26 11:37:58 +01:00
mhajas e2ad59a74d KEYCLOAK-4816 KEYCLOAK-4817 Move javascript tests to base testsuite and (#4964)
* KEYCLOAK-4816 KEYCLOAK-4817 Move javascript tests to base testsuite and
use JavascriptExecutor

* Use PhantomJS 2.1.1 instead of 1.9.8 in Travis CI
2018-02-26 10:49:05 +01:00
Ismael Jimenez f604449188 Removed duplicated tabindex
The tabindex="3" was at the beginning and at the end of the tag, kept the one at the beginning for consistency.
2018-02-26 10:47:32 +01:00
Tomas Kyjovsky f3b965d466 KEYCLOAK-5372 Add warm-up, test-time, ramp-down times 2018-02-23 20:24:19 +01:00
Hynek Mlnarik e7cdb8ad54 KEYCLOAK-6473 KEYCLOAK-6472 SAML parser refactor + protocol parsers 2018-02-23 08:16:14 +01:00
gonzalad 898347366d KEYCLOAK-6589: Optimize jpql in User search API
This commit removes the 6 n+1 select
that are issued when calling GET /users api.

We now have 4 select queries.
2018-02-22 14:21:42 +01:00
Stian Thorgersen 9ef1f1b73c KEYCLOAK-3482 2018-02-22 09:42:45 -03:00
Marko Strukelj eea6eb6263 KEYCLOAK-6664 Fix performance testsuite shell scripts to run on macOS 2018-02-22 12:40:23 +01:00
Marko Strukelj 548ab4f78c KEYCLOAK-6514 Common approach to writing performance tests 2018-02-22 12:40:04 +01:00
pedroigor b464dc15f2 [KEYCLOAK-6492] - Removing resources files 2018-02-22 09:05:40 +01:00
pedroigor 8112c5d3f2 [KEYCLOAK-6492] - Migrate authorization package from old testsuite 2018-02-22 09:05:40 +01:00
stianst eb326cd1bb KEYCLOAK-6534 Check for string in receiveMessage in session iframe 2018-02-22 07:02:16 +01:00
Erlend Hamnaberg 208ecbc3f7 KEYCLOAK-6676: Fix NPE if the redirect_uri parameter is missing 2018-02-21 19:44:22 +01:00
pedroigor 61d5425fdf [KEYCLOAK-6321] - Tests 2018-02-21 19:41:44 +01:00
pedroigor d590600c12 [KEYCLOAK-6321] - NPE when deleting a resource with admin events enabled 2018-02-21 19:41:44 +01:00
Hynek Mlnarik 12a2f23101 KEYCLOAK-6651 Fix JDK7 compilation issue 2018-02-21 09:43:04 +01:00
Bruno Oliveira f351db608e [KEYCLOAK-6334] Minor typo: "read only" should be "read-only" 2018-02-20 20:18:16 +01:00
Christian Katzorke (cig393a) 2c59d948fc in addition to KEYCLOAK-6065 no automplete 2018-02-20 20:14:28 +01:00
Tomas Kyjovsky 72199cc0b3 KEYCLOAK-6582 Specify exact version of MariaDB server in the performance tests 2018-02-19 11:53:45 +01:00
mposolda fc463ae50b KEYCLOAK-6617 Offline token logout did not invalidate user session 2018-02-19 08:49:05 +01:00
cgol 86a8addf49 KEYCLOAK-6615 Remove offline session from database on offline token logout
remove offline token from database on offline session logout
2018-02-19 08:49:05 +01:00
Hynek Mlnarik b367e94261 KEYCLOAK-6522 Align versions 2018-02-16 10:45:36 +01:00
Tomas Kyjovsky df68ca8dcf KEYCLOAK-5968 Move configuration of Infinispan server from Dockerfile to maven 2018-02-14 16:48:22 +01:00
stianst 9b63cd35f0 KEYCLOAK-6431 2018-02-13 19:38:46 +01:00
Hynek Mlnarik 84ea3f8cb1 KEYCLOAK-4315 Remove some dead/duplicate classes 2018-02-13 15:41:36 +01:00
Bill Burke 5d5373454c Merge pull request #4991 from patriot1burke/challenge-support
KEYCLOAK-6355
2018-02-13 09:38:45 -05:00
Bill Burke a3d6917f20 disable clisso experimental feature 2018-02-12 17:57:05 -05:00
Bill Burke 87ee15a081 fix 2018-02-12 16:52:55 -05:00
David Festal f44cda2621 Make the keycloak.js capable of working with alternate OIDC providers (#4978)
* Make the `keycloak.js` capable of working with alternate OIDC providers

(provided that they create access_tokens as JWT tokens with `exp` and
`iat` claims).

Also add a `useNonce` option, to allow disabling the `nonce` check
since, in the OIDC specification, `nonce` is optional.

Signed-off-by: David Festal <dfestal@redhat.com>

* Update the `keycloak.ts` with the `useNonce` additional init option. 

Signed-off-by: David Festal <dfestal@redhat.com>

* Fix 2 errors in the case `checkSessionIframe` is used

Signed-off-by: David Festal <dfestal@redhat.com>
2018-02-12 11:00:02 +01:00
stianst dd1e5b5c0f Fix JS console update profile 2018-02-12 10:25:43 +01:00
Stian Thorgersen adb6c7789c Merge pull request #4967 from k-tamura/fix-incorrect-japanese-translations
KEYCLOAK-6469 Fix incorrect Japanese translations
2018-02-12 09:58:58 +01:00
Bill Burke d6788a0839 finish 2018-02-10 13:38:39 -05:00
mhajas 2b65adc15f KEYCLOAK-6309 Fix tests
Add trustore to war even if ssl is not enabled because HttpClient is configured with truststore
2018-02-09 10:24:58 +01:00
Bruno Oliveira b91998a0d8 [KEYCLOAK-6111] 'Override User-Initiated Action Lifespan' admin GUI can break realm configuration 2018-02-09 06:36:23 -02:00
stianst 505cf5b251 KEYCLOAK-6519 Theme resource provider 2018-02-09 08:28:59 +01:00
Bill Burke 5ea4ef9e55 change code query params to session_code 2018-02-08 17:37:27 -05:00
Douglas Palmer e8de4655ac KEYCLOAK-6344 Use POST instead of GET for LDAP connection tests 2018-02-08 21:18:03 +01:00
pedroigor 76657d5239 [KEYCLOAK-6528] - Fixing mysql error. Probably a consequence of KEYCLOAK-6228 changes. 2018-02-08 21:17:33 +01:00
Stian Thorgersen d63040283f Merge pull request #4958 from iilei/missing_accept_language_country_code_fallback
Fix Locale Negotiation for omitted Country Code
2018-02-08 20:55:19 +01:00
Josh Cain 04c2ad9430 give more useful failure message when event.error is called without first setting event.type 2018-02-08 16:20:16 +01:00
Stian Thorgersen 75f040f38e Merge pull request #4979 from stianst/KEYCLOAK-1874
KEYCLOAK-1874 Add PatternFly 3.38.1
2018-02-07 15:29:01 +01:00
stianst 0e69dc6885 KEYCLOAK-1874 Add PatternFly 3.38.1 2018-02-07 14:26:10 +01:00
stianst f1e7d3d6da KEYCLOAK-6378 Clean themes common directory 2018-02-07 12:07:40 +01:00
Hynek Mlnarik c07b60d527 KEYCLOAK-6474 Fix NPE on SAML logout 2018-02-07 08:05:36 +01:00
David 2743e4a182 Update changes on sssd.conf file to make script idempotent 2018-02-06 09:04:37 -02:00
Hynek Mlnarik 972c3dd36b KEYCLOAK-6521 Update licenses 2018-02-06 11:58:11 +01:00
Martin Kanis 9ccef223f6 KEYCLOAK-6522 Align versions to match EAP 7.1.1 2018-02-06 11:58:11 +01:00
Douglas Palmer fc52ff65bd [KEYCLOAK-6518] Added explicit guava dependency instead of relying on transitive dependency. 2018-02-06 10:52:48 +01:00
Jochen Preusche 8325151e16 Extract findLocale to LocaleNegotiator, add tests
* Improve Testability of Locale Negotiation
 * Add test for Locale Negotiation
 * Fix Locale Negotiation for omitted Country Code
2018-02-06 09:50:04 +01:00
Hynek Mlnarik b3766576d7 KEYCLOAK-6146 Simplify test via RealmCreator 2018-02-06 09:28:07 +01:00
Pedro Igor e3153295a9 Merge pull request #4969 from vmuzikar/fix-authz-tests
KEYCLOAK-6509 Stabilize authz rules UI tests
2018-02-05 17:06:43 -02:00
vmuzikar 3420293f36 KEYCLOAK-6509 Set waiting period in RulePolicyForm to longer value 2018-02-05 15:47:44 +01:00
Kohei Tamura 0370cb64e7 Fix incorrect Japanese translations 2018-02-05 19:11:03 +09:00
Kohei Tamura a50b94be0c KEYCLOAK-6457 Fix typos in properties 2018-02-05 05:58:08 +01:00
Marko Strukelj 62a9d4ea91 KEYCLOAK-5807 Under daily eviction policy user entries not returned from cache when they should 2018-02-02 19:27:23 +01:00
Serhii Shymkiv c2fe500eb8 [KEYCLOAK-4721] Consider Session Language of Realm Also In ReCaptcha 2018-02-02 13:57:03 +01:00
vmuzikar 340afb2a50 KEYCLOAK-6450 Stabilize WelcomePageTest 2018-02-02 13:08:52 +01:00
Tomas Kyjovsky 3873ab811a KEYCLOAK-6288 Add support for "sar" metrics for docker-based performance testing 2018-02-02 12:44:33 +01:00
Tomas Kyjovsky 4ab856a0be KEYCLOAK-6140 Allow to customize max_connections parameter of MariaDB server 2018-02-02 12:43:01 +01:00
vmuzikar 46ebff2163 KEYCLOAK-6331 Fix and stabilize Console UI tests 2018-02-02 11:58:47 +01:00
Hynek Mlnarik afa26f7d3c KEYCLOAK-6339 Display SAML client IdP-initiated SSO URL 2018-02-02 11:17:10 +01:00
Pavel Drozd 9382439a05 Merge pull request #4944 from mhajas/KEYCLOAK-4751
KEYCLOAK-4751 Fix tests on EAP6 and add test for EAP7
2018-02-02 11:13:07 +01:00
o.pakers 8495a7c05a [master]: fix type for checkLoginIframeInterval 2018-02-02 08:37:07 +01:00
vramik 019c3c9ef9 KEYCLOAK-6146 realm import fails when password policy is specified 2018-02-02 08:30:06 +01:00
Thomas Darimont 77334af34e KEYCLOAK-6222 Check syntax for errors on ScriptBasedOIDCProtocolMapper validation
We now explicitly check for syntax errors
during validation of ScriptBasedOIDCProtocolMappers.
2018-02-02 08:28:27 +01:00
Bill Burke 8f09efab9d Merge pull request #4949 from patriot1burke/client-storage-spi
KEYCLOAK-6228
2018-02-01 08:59:02 -05:00
mhajas c34db4cf01 KEYCLOAK-6309 Configure HTTPClient in keycloak-saml.xml 2018-02-01 09:59:08 +01:00
Bill Burke 6054b69eec fix serializable exceptions 2018-01-31 20:26:50 -05:00
Martin Kanis 6b8ec0bb82 KEYCLOAK-6154 Exclude common-logging/codec from keycloak-osgi-thirdparty 2018-01-31 21:26:41 +01:00
Bill Burke a0d275c850 whoops, fix db script 2018-01-31 14:28:40 -05:00
Bruno Oliveira 179e371d0e [KEYCLOAK-6298] SAML adapter script should support offline installation of adapter 2018-01-31 17:10:31 -02:00
Bill Burke 26411a123e migrate fix 2018-01-31 13:11:46 -05:00
Bill Burke 126dd70efc client stat improvement 2018-01-31 13:05:13 -05:00
Pedro Igor 461c62ea10 Merge pull request #4953 from pedroigor/KEYCLOAK-6164
[KEYCLOAK-6164] - Authorization services client doesn't work with JDK7
2018-01-31 15:18:50 -02:00
pedroigor bda57d00df [KEYCLOAK-6164] - Authorization services client doesn't work with JDK7 2018-01-31 13:42:30 -02:00
Bill Burke bd3eb9d662 more hynek db changes 2018-01-30 19:46:42 -05:00
Bill Burke a571781240 hynek db changes 2018-01-30 17:00:55 -05:00
Vlastimil Elias a5f675d693 KEYCLOAK-4937 - convert time units in emails into human-friendly format 2018-01-30 06:38:57 +01:00
Bill Burke 4a044fe867 add ofline token test 2018-01-29 17:08:13 -05:00
Bill Burke 0fc7fa557d fix caching 2018-01-29 16:26:51 -05:00
Bill Burke 79f9de9de4 Merge remote-tracking branch 'upstream/master' into client-storage-spi 2018-01-29 12:28:26 -05:00
Bill Burke 4bf23cc83a caching 2018-01-29 12:28:17 -05:00
Pedro Igor 82815ff614 Merge pull request #4943 from mhajas/KEYCLOAK-6392
KEYCLOAK-6392 Install elytron adapter on windows
2018-01-29 09:35:12 -02:00
Pedro Igor bdfab04c10 Merge pull request #4948 from mhajas/KEYCLOAK-4793
KEYCLOAK-4793 Fix authorization services maven scanner properties in …
2018-01-29 09:33:58 -02:00
mhajas 2a2f255640 KEYCLOAK-4793 Fix authorization services maven scanner properties in base testsuite for product 2018-01-29 09:18:20 +01:00
Bill Burke 1d8e38f0c6 admin console 2018-01-27 13:05:02 -05:00
Bill Burke dd4c0d448c Merge remote-tracking branch 'upstream/master' into client-storage-spi 2018-01-27 09:47:41 -05:00
Bill Burke 6b84b9b4b6 done 1st iteration 2018-01-27 09:47:16 -05:00
mhajas 8ac7d1deca KEYCLOAK-4751 Fix tests on EAP6 and add test for EAP7 2018-01-26 11:25:33 +01:00
mhajas f0511c5f51 KEYCLOAK-6392 Install elytron adapter on windows 2018-01-26 11:21:53 +01:00
Takashi Norimatsu 502627f590 KEYCLOAK-5811 Client Authentication by JWS Client Assertion in client secret 2018-01-26 10:59:40 +01:00
vmuzikar 806b554fb2 Social login test for GitHub with private email 2018-01-25 20:56:24 +01:00
gregoirew 13261b52db Use the github /user/emails api endpoint if the github user did not set any public email.
Github can send a null email on the user info endpoint if there is no public email on the user profile.
This commit look for email on the /user/emails endpoint, selecting the primary email.
2018-01-25 20:56:24 +01:00
Ray DeCampo a21a94078b KEYCLOAK-5578: Keycloak JS adapter returns native Promise instances when available.
Promise instances are adorned with success() and error() functions to retain backwards compatibility.
2018-01-25 20:42:31 +01:00
vramik b0fbe5c8ba KEYCLOAK-6300 List of group members is not sorted alphabetically 2018-01-25 20:21:03 +01:00
Bill Burke ddad1cb8af Merge remote-tracking branch 'upstream/master' into client-storage-spi 2018-01-25 10:08:37 -05:00
Bill Burke 8a17b61f4e initial work 2018-01-25 10:08:26 -05:00
Bill Burke 7c66f76858 Merge pull request #4932 from patriot1burke/per-client-flow
KEYCLOAK-6335
2018-01-25 09:55:11 -05:00
Thomas Darimont 3d12bf7d14 KEYCLOAK-4743 Revise proxy support for HttpClient SPI
Polishing & more tests.
2018-01-25 09:31:32 +01:00
Thomas Darimont 851d0192ad KEYCLOAK-4743 Add proxy support to HttpClient SPI
We now provide a configurable way for dynamic proxy route selection
for the default HttpClient based on regex based targetHostname patterns.

Introduced `ProxyMapping` to describe a regex based mapping
between target hosts and the proxy URL to use.

A `ProxyMapping` can be build from an ordered list of string based
mapping representations, e.g:
```
   ^.*.(google.com|googleapis.com)$;http://localhost:8080
```
If the targetHost does not match a configured proxy mapping,
no proxy is used.

This can be configured via standalone.xml / jboss-cli, e.g.:
```
   echo SETUP: Configure proxy routes for HttpClient SPI
   /subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:add(enabled=true)
   /subsystem=keycloak-server/spi=connectionsHttpClient/provider=default:write-attribute(name=properties.proxy-mappings,value=["^.*.(google.com|googleapis.com)$;http://www-proxy1:8080","^.*.facebook.com$;http://www-proxy2:8080"])
```
The new `ProxyMappingWareRoutePlanner` uses a configured `ProxyMapping`
to decide which proxy to use for a given request based on the target host
denoted by the HTTP request to execute.

I verified this manually with the BurpProxy Suite.
2018-01-25 09:31:32 +01:00
Douglas Palmer 42759be6ff [KEYCLOAK-6143] Remove Hmac prefix from algorithms in the OTP manual config pages 2018-01-25 07:10:30 +01:00
Douglas Palmer 0f1644e612 [KEYCLOAK-6142] Updated OTP manual config pages to reflect HOTP 2018-01-25 07:09:24 +01:00
Thorsten Boock 64b75d2806 Fix Authenticator Page HTML
Closes `<thead>` and disables escaping for the `totpStep1` message as it includes HTML links.
2018-01-24 13:44:57 -05:00
Bill Burke 4bfb62d7f4 marek suggested fixes 2018-01-24 09:32:38 -05:00
mposolda 6369c26671 KEYCLOAK-6286 Adding 'Exclude Session State From Authentication Response' switch to fix backwards compatibility with Keycloak 2.X adapters 2018-01-24 11:35:13 +01:00
Thomas Recloux 71e0b00600 KEYCLOAK-5857 Supports PBKDF2 hashes with different key size
The original use case is to support imported credentials with a different key size without
implementing a totally new PasswordHashProvider
2018-01-24 09:02:37 +01:00
Bill Burke be65c14a6a fix provider test 2018-01-23 13:03:45 -05:00
Bill Burke 7b2e72d395 Merge remote-tracking branch 'upstream/master' into per-client-flow 2018-01-23 12:10:11 -05:00
Bill Burke a9297df89c KEYCLOAK-6335 2018-01-23 12:09:49 -05:00
Hynek Mlnarik 4ba72e2d2d KEYCLOAK-5976 Fix client setting in brokered IdP-initiated scenario 2018-01-23 09:34:11 +01:00
Tomas Kyjovsky 5f49db6c7f KEYCLOAK-6311 Remote-mode adapter tests don't work 2018-01-19 15:09:57 +01:00
Douglas Palmer fc3c07f6de [KEYCLOAK-6236] Use MessageDigest.isEquals in place of String.equals 2018-01-18 13:04:54 +01:00
Hynek Mlnarik c7cba6d5ad KEYCLOAK-6109 Skip Scoping element in AuthnRequest 2018-01-18 11:40:13 +01:00
Martin Kanis 6f624b29e4 KEYCLOAK-6240 Exclude events doesn't work in examples 2018-01-18 11:10:13 +01:00
stianst f762173eb0 KEYCLOAK-3370 Add option to override theme in client template and client 2018-01-18 09:14:13 +01:00
stianst 35ada9d636 KEYCLOAK-6289 Add ThemeSelectorSPI 2018-01-18 09:14:13 +01:00
stianst 81a4ba854c KEYCLOAK-6136 Set target/source 2018-01-16 15:12:28 +01:00
Tomas Kyjovsky 5758c7e175 KEYCLOAK-6138 Allow to customize version of the KC server artifact used in performance tests 2018-01-12 14:11:41 +01:00
Tomas Kyjovsky ba2f8cdeef KEYCLOAK-6085 Allow to customize DB dump download location through a Maven property 2018-01-12 14:11:10 +01:00
Pavel Drozd c2fa2de290 Merge pull request #4911 from wyvie/springboot-jetty
[KEYCLOAK-3837] jetty version can be passed as argument for springboot tests
2018-01-12 11:58:14 +01:00
Pedro Igor 932aef887c Merge pull request #4913 from pedroigor/KEYCLOAK-6159
[KEYCLOAK-6159] - Resource Permission UI not enabling save button when no policies are set
2018-01-11 10:41:20 -02:00
Thomas Darimont bae4d4c673 KEYCLOAK-5791 Allow multi-valued ScriptBasedOIDCProtocolMapper
We now support multi-valued attribute values for the
`ScriptBasedOIDCProtocolMapper`.
Previously the `ScriptBasedOIDCProtocolMapper` only supported
single valued output. If a script returned a list of
output values then only the first value was emitted to the token.

By default multi-valued is set to `false` / `off`.
2018-01-11 08:52:24 +01:00
Pedro Igor 6bf050e05c Merge pull request #4912 from mhajas/KEYCLOAK-5503
KEYCLOAK-5503 Remove redirecting to error page for AutodetectBearerOn…
2018-01-10 15:28:52 -02:00
pedroigor 79349e6307 [KEYCLOAK-6159] - Resource Permission UI not enabling save button when no policies are set 2018-01-09 16:28:53 -02:00
mhajas a77be7eb7b KEYCLOAK-5503 Remove redirecting to error page for AutodetectBearerOnly client 2018-01-09 16:34:18 +01:00
wyvie 082714a436 [KEYCLOAK-3837] jetty version can be passed as argument for springboot tests 2018-01-09 16:15:31 +01:00
stianst 06bb6f00e5 Include Jetty 9.1 in product profile 2018-01-04 09:14:11 +01:00
Hynek Mlnarik e4c875eb41 KEYCLOAK-6108 Remove DROP INDEX in postgres (handled automatically) 2018-01-04 09:03:52 +01:00
Hynek Mlnarik f0c1e65b2d KEYCLOAK-6095 Include schema in custom SQL 2018-01-04 09:03:52 +01:00
Hynek Mlnarik b5fc6045fd KEYCLOAK-6106 Put dotless ids first in identity broker state 2018-01-02 21:31:49 +01:00
Pedro Igor d99dcc0d4b Merge pull request #4898 from pedroigor/KEYCLOAK-6113
[KEYCLOAK-6113] - Remove red asterisk sign next to 'Apply Policy' while creating a new permission
2018-01-02 13:40:53 -02:00
pedroigor 56750cba83 [KEYCLOAK-6113] - Remove red asterisk sign next to 'Apply Policy' while creating a new permission 2018-01-02 12:40:10 -02:00
stianst 6e3303145f KEYCLOAK-6079 2018-01-02 15:15:44 +01:00
stianst d8c0cc447f KEYCLOAK-6090 Add missing cors headers with invalid username/password and resource owner grant 2018-01-02 15:15:15 +01:00
Ramon Spahr 3ee999ae2a fix wrong file path and extension for welcome-theme example 2018-01-02 12:11:44 +01:00
stianst 0bedbb4dd3 Bump version to 4.0.0.CR1-SNAPSHOT 2017-12-21 15:06:00 +01:00
Marko Strukelj 23d0afbfd8 KEYCLOAK-6058 Partial import should ignore built-in clients 2017-12-21 13:52:58 +01:00
stianst e3995c0154 KEYCLOAK-6079 2017-12-21 12:18:12 +01:00
stianst e4185496fd KEYCLOAK-6078
Account2 is listed as disabled feature in product even though it's not included at all
2017-12-21 11:45:00 +01:00
stianst c7ce279aef KEYCLOAK-6076 Exclude transitive dependencies in Fuse ZIP 2017-12-21 09:03:21 +01:00
John Ament 156ce0c0ea KEYCLOAK-4853 Introduce dedicated utility for parsing ID from URI 2017-12-20 15:00:07 +01:00
Hynek Mlnarik 0f047ac9f5 KEYCLOAK-6067 Allow http for performance testsuite realms 2017-12-20 14:56:42 +01:00
stianst f0c5752ef9 KEYCLOAK-5443 Fix update user account when both email as username and edit username are enabled 2017-12-20 14:40:03 +01:00
Martin Kanis 351dbffaf2 KEYCLOAK-5172 Set oidc as default protocol to clients 2017-12-20 13:38:12 +01:00
Bruno Oliveira 811cd3a04a KEYCLOAK-6011 2017-12-20 13:37:11 +01:00
Marko Strukelj ae573f4814 KEYCLOAK-5617 KEYCLOAK-5993 Race condition putting new user in user cache 2017-12-20 13:35:35 +01:00
Pedro Igor 7e072abf74 Merge pull request #4873 from pedroigor/master
[KEYCLOAK-5806] - Returning from child policy not restoring state
2017-12-20 08:53:50 -02:00
stianst e96c6a4bcb KEYCLOAK-6068 Fix preflight request on admin endpoints 2017-12-20 10:19:34 +01:00
stianst 7d2d7e41d9 KEYCLOAK-6065 Prevent password managers from saving credentials in admin console 2017-12-20 06:46:54 +01:00
Hynek Mlnarik 626004e782 KEYCLOAK-6066 Be less strict when handling cookies 2017-12-19 21:39:41 +01:00
pedroigor 3846cfdb4f [KEYCLOAK-5806] - Changing apply policy component and more tests 2017-12-19 17:28:46 -02:00
stianst 902b799bdf KEYCLOAK-6064 Fix identity providers page when realm has no configured providers 2017-12-19 17:56:48 +01:00
stianst 465675ac28 KEYCLOAK-5019 Fixes for password managers 2017-12-19 16:13:16 +01:00
pedroigor 2ace312501 [KEYCLOAK-5806] - More UI tests for parent/child policy flow 2017-12-19 12:13:04 -02:00
pedroigor c00d89aec3 [KEYCLOAK-5806] - Returning from child policy not restoring state 2017-12-19 10:00:14 -02:00
stianst 61fe554617 KEYCLOAK-6051 Fix licenses 2017-12-19 08:20:29 +01:00
mposolda 5a66f577eb KEYCLOAK-5982 Fix NPEs when client 'account' was renamed/removed 2017-12-18 21:47:17 +01:00
pskopek e29ccebc21 KEYCLOAK-5666 removed not needed decodeToObject methods 2017-12-18 19:19:00 +01:00
stianst 27b5e1aae2 KEYCLOAK-6050 Fix export doesn't export internal realm rep 2017-12-18 13:15:42 +01:00
stianst 71e6f52f7d KEYCLOAK-6022 2017-12-18 11:48:39 +01:00
stianst b303acaaba KEYCLOAK-2120 Added manual setup page for OTP 2017-12-18 11:20:20 +01:00
Bill Burke 118e998570 Merge pull request #4834 from pedroigor/KEYCLOAK-5806
[KEYCLOAK-5806] - Create policy button to associated policies
2017-12-16 23:44:35 -05:00
Bill Burke f3fcac2d8d Merge pull request #4865 from patriot1burke/master
KEYCLOAK-5420
2017-12-16 14:31:37 -05:00
Bill Burke b5ae7e836d smaller times 2017-12-16 13:18:41 -05:00
Bill Burke a27097e9ef reset defaults 2017-12-16 11:28:15 -05:00
Bill Burke 003f27e9bd fix more 2017-12-16 08:31:33 -05:00
Bill Burke 76cccc3f2b fix more 2017-12-16 08:29:58 -05:00
Bill Burke 80be4c9dbc fix more 2017-12-16 07:12:32 -05:00
pedroigor 5d7ba39e0c [KEYCLOAK-5806] - Create policy component to permission pages 2017-12-15 23:41:52 -02:00
pedroigor e2118856ca [KEYCLOAK-5806] - Adding table of selected policies 2017-12-15 22:04:37 -02:00
pedroigor 3ee760ed23 [KEYCLOAK-5806] - More tests asserting creation of child policies 2017-12-15 22:04:37 -02:00
pedroigor eba47b3c89 [KEYCLOAK-5806] - Create policy button to Aggregated Policies 2017-12-15 22:04:37 -02:00
Pavel Drozd b121306749 Merge pull request #4866 from pdrozd/KEYCLOAK-6054
KEYCLOAK-6054 Fuse adapter tests - add httpclient dependency
2017-12-15 23:44:33 +01:00
Pavel Drozd 4097a81142 Merge pull request #4860 from pdrozd/KEYCLOAK-6047
KEYCLOAK-6047 Added ide time window to mellon test
2017-12-15 22:23:19 +01:00
Pavel Drozd ce6f73ce74 KEYCLOAK-6054 Fuse adapter tests - add httpclient dependency 2017-12-15 22:22:16 +01:00
Bill Burke 1eec2747ef fix stupidity 2017-12-15 15:31:14 -05:00
Pedro Igor 6bfdc9451d Merge pull request #4861 from pedroigor/KEYCLOAK-6023
[KEYCLOAK-6023] - Upgrading Drools to 6.5.0.Final
2017-12-15 15:46:28 -02:00
Pedro Igor a66fe003d3 Merge pull request #4863 from pedroigor/KEYCLOAK-5877
[KEYCLOAK-5877] - Allow save permissions without policies
2017-12-15 15:45:38 -02:00
Bill Burke 7cb39c2dfc KEYCLOAK-5420 2017-12-15 12:16:24 -05:00
Bill Burke 90b5dd60fd Merge pull request #4864 from patriot1burke/master
KEYCLOAK-4427
2017-12-15 11:44:16 -05:00
Stan Silvert a719b73808 KEYCLOAK-5935: No success msg on client role add/remove 2017-12-15 10:54:43 -05:00
Bill Burke 1c38cec10f KEYCLOAK-4427 2017-12-15 10:53:13 -05:00
Bill Burke e7c25f76a7 KEYCLOAK-4427 2017-12-15 10:49:51 -05:00
pedroigor 94928323ee [KEYCLOAK-5877] - Allow saving permissions without policies 2017-12-15 12:55:07 -02:00
Hynek Mlnarik e4a91c0706 KEYCLOAK-6042 Encode user ID before storing in auth session 2017-12-15 15:16:26 +01:00
Pavel Drozd a7c6eb4999 KEYCLOAK-6047 Added ide time window to mellon test 2017-12-15 14:57:26 +01:00
Pavel Drozd 1b14f9e73e Merge pull request #4847 from vramik/KEYCLOAK-4793
KEYCLOAK-4793 moved profile a lever lower due to migration test
2017-12-15 14:52:04 +01:00
pedroigor 569378b446 [KEYCLOAK-6023] - Upgrading Drools to 6.5.0.Final 2017-12-15 10:22:05 -02:00
stianst a8943fb323 KEYCLOAK-6043 Use same urls for get and posts in account 2017-12-15 08:31:04 +01:00
Bruno Oliveira 1a541889f4 [KEYCLOAK-6015] replyTo can be empty string in DB 2017-12-15 07:01:15 +01:00
stianst b672229efc KEYCLOAK-6032 Fix error page when internationalization is enabled 2017-12-15 06:32:00 +01:00
Stan Silvert 2b11938084 KEYCLOAK-5932: Remove social idp from dropdown if already defined 2017-12-14 20:18:56 -05:00
Stan Silvert 97e3b26a5c KEYCLOAK-5934: Event filters allowing free values in select2 inputs 2017-12-14 16:38:02 -05:00
Vlastimil Elias 7e20a65989 KEYCLOAK-6040 AuthenticationSessionModel pushing into
EmailTemplateProvider
2017-12-14 15:51:04 +01:00
Martin Kanis 47721957b7 KEYCLOAK-6018 Create BOM for Drools dependencies 2017-12-14 14:51:25 +01:00
Stan Silvert 068785f227 KEYCLOAK-6042: Remove keycloak-preview from product build. 2017-12-14 14:09:04 +01:00
sebastienblanc a96c9d34c9 set auth contraint to true when wildcard is used 2017-12-14 14:00:03 +01:00
Hisanobu Okuda 3d0512efd8 KEYCLOAK-3842 SPNEGO: Support for multiple kerberos realms 2017-12-14 12:54:20 +01:00
vramik abea430802 KEYCLOAK-4793 2017-12-14 11:30:28 +01:00
Hynek Mlnarik 2a2e6c839b KEYCLOAK-5635 2017-12-13 21:07:46 +01:00
mposolda 6696c0f0b2 KEYCLOAK-5245 Restart failures when deleting a client with existing sessions/offline_tokens 2017-12-13 15:53:10 +01:00
Hynek Mlnarik 958185ec51 KEYCLOAK-4809 Support for SAML AttributeAuthorityDescriptor.Attribute elements 2017-12-13 11:55:40 +01:00
Hynek Mlnarik e6a64e234b KEYCLOAK-5644 Skip Advice tag in SAML messages 2017-12-13 11:55:40 +01:00
mposolda b793e42c53 KEYCLOAK-5017 Adding user to newly created group caused sync all groups to LDAP 2017-12-13 09:15:47 +01:00
Bill Burke f80811a065 Merge pull request #4841 from patriot1burke/master
KEYCLOAK-5923
2017-12-12 16:07:52 -05:00
Bill Burke ea3417253f KEYCLOAK-5923 2017-12-12 16:07:09 -05:00
Hynek Mlnarik 7174c0b4ec KEYCLOAK-6025 Simplify easy access to current session in action token handlers 2017-12-12 17:53:44 +01:00
Bruno Oliveira 0a9055e112 [KEYCLOAK-5175] Importing certificate to saml client takes too long 2017-12-12 14:45:24 +01:00
stianst f939818252 KEYCLOAK-5907 Use client manager to delete clients in client registration services 2017-12-12 14:25:05 +01:00
mposolda b8416dfa3e KEYCLOAK-5981 Test Impersonation works when authenticationSession exists 2017-12-12 09:43:34 +01:00
mposolda 63efee6e15 KEYCLOAK-5938 Authentication sessions: Support for logins of multiple tabs of same client 2017-12-12 08:01:02 +01:00
Pavel Drozd c3855510ef Merge pull request #4822 from vmuzikar/fix-nodejs-test
KEYCLOAK-6007 Fix failing integration Node.js adapter test
2017-12-12 00:10:37 +01:00
Pavel Drozd 20f8e5e572 Merge pull request #4821 from mhajas/KEYCLOAK-6005
KEYCLOAK-6005 Fail build when adapters installation fails
2017-12-12 00:09:45 +01:00
Pavel Drozd 047fdb55a2 Merge pull request #4803 from mhajas/KEYCLOAK-5896
KEYCLOAK-5896 Run localization test only in community
2017-12-12 00:09:02 +01:00
Pavel Drozd be36f5358c Merge pull request #4802 from mhajas/KEYCLOAK-5986
KEYCLOAK-5986 Fix token javacsript tests
2017-12-12 00:07:16 +01:00
Pavel Drozd 21dcea87c5 Merge pull request #4795 from mhajas/KEYCLOAK-4995
KEYCLOAK-4995 Fix Cluster tests on product and wildfly 10
2017-12-12 00:06:35 +01:00
Bruno Oliveira 79c4d3e7cf [KEYCLOAK-6002] - keycloak-test-helper should use the same resteasy dependency version as the parent 2017-12-11 14:34:28 +01:00
Stan Silvert a60fdcedcd KEYCLOAK-5929: Submit buttons in wrong position 2017-12-11 08:27:39 -05:00
stianst dac6c6bd7e KEYCLOAK-6000 Fix output in execute actions email 2017-12-11 14:24:37 +01:00
stianst 867de9de50 KEYCLOAK-6010 Add CORS headers to keycloak.js 2017-12-11 14:24:12 +01:00
stianst 74442ae820 Added script to check Java version in JARs within ZIPs 2017-12-11 13:15:24 +01:00
k-tamura d7a90817f2 KEYCLOAK-6009 Fix incorrect String.format usage 2017-12-10 20:56:36 +01:00
Bill Burke c9b218db71 Merge pull request #4823 from patriot1burke/master
KEYCLOAK-5724
2017-12-08 20:03:05 -05:00
Bill Burke 7c031505e2 add test 2017-12-08 17:38:00 -05:00
Tomas Kyjovsky 03e43f8964 KEYCLOAK-5966 Adjust defaults for performance testsuite provisioning 2017-12-08 21:06:12 +01:00
Tomas Kyjovsky b5c7be574b KEYCLOAK-5967 Move configuration of load-balancer from Dockerfile to maven 2017-12-08 21:05:26 +01:00
Bill Burke eea315a83b KEYCLOAK-5724 2017-12-08 10:26:28 -05:00
Bill Burke ce9f4bf97a KEYCLOAK-5724 2017-12-08 10:25:30 -05:00
Bill Burke 5d5a200413 Merge pull request #4818 from patriot1burke/master
KEYCLOAK-5926
2017-12-08 09:59:32 -05:00
vmuzikar 874dbcb3e1 KEYCLOAK-6007 Fix failing integration Node.js adapter test 2017-12-08 15:46:17 +01:00
mhajas 10219c1157 KEYCLOAK-6005 Fail build when adapters installation fails 2017-12-08 13:32:44 +01:00
Hynek Mlnarik 00fb36437d KEYCLOAK-5861 Remove AUTH_SESSION_ID when END_AFTER_REQUIRED_ACTIONS set 2017-12-08 09:52:14 +01:00
Hynek Mlnarik 4a012b73ea KEYCLOAK-4998 Fix NPE in AttributeToRoleMapper 2017-12-08 09:21:21 +01:00
Bill Burke fce16fe030 last fix 2017-12-08 02:30:48 -05:00
Bill Burke 67149ce3c3 fix test 2017-12-08 02:23:41 -05:00
Bill Burke 49ba71fd8f add logic for sync 2017-12-07 20:03:10 -05:00
Bill Burke 0dee393071 KEYCLOAK-5926 2017-12-07 19:49:10 -05:00
Bill Burke 464535ac81 Merge pull request #4815 from abstractj/KEYCLOAK-5467-i18-buttons
KEYCLOAK-5467 X.509 Auth - missing internationalization support
2017-12-07 10:08:11 -05:00
Bill Burke efa5949f69 Merge pull request #4814 from patriot1burke/master
KEYCLOAK-5350
2017-12-07 10:07:35 -05:00
Bruno Oliveira 3f3d50b9ad KEYCLOAK-5467 X.509 Auth - missing internationalization support
This adds the missing i18n support for login buttons
2017-12-07 08:52:16 -02:00
Pavel Drozd e567dcb888 Merge pull request #4809 from vramik/KEYCLOAK-4641
KEYCLOAK-4641 migrate remaining Adapter tests from old testsuite
2017-12-07 11:06:47 +01:00
stianst f2ba699520 Update RH-SSO target version 2017-12-07 10:46:13 +01:00
stianst c055ffb083 KEYCLOAK-4215 Consider session expiration when setting token timeouts 2017-12-07 10:45:02 +01:00
stianst 5fd3c9161d KEYCLOAK-5868 2017-12-07 10:42:21 +01:00
Tomas Kyjovsky 5fd00a0def KEYCLOAK-5971 Replace "numOfIterations" parameter with "steadyLoadPeriod" 2017-12-06 22:46:53 +01:00
Bill Burke 64f8d7ce25 KEYCLOAK-5350 2017-12-06 16:00:23 -05:00
Stan Silvert b8da95e901 KEYCLOAK-5930: Submit button on cred screen should start as disabled 2017-12-06 15:35:00 -05:00
stianst cccddebfd0 KEYCLOAK-5984 Fix error message in client initiated 2017-12-06 19:46:11 +01:00
vramik 5a8ff72cb6 KEYCLOAK-4641 migrate remaining Adapter tests from old testsuite 2017-12-06 15:12:37 +01:00
stianst ecfabe4ebe KEYCLOAK-5913 Move Chinese translations into resources-community 2017-12-06 13:58:52 +01:00
mposolda 8a0fa521c4 KEYCLOAK-5915 Support for sticky sessions managed by loadbalancer. Support for KeyAffinityService 2017-12-06 13:06:54 +01:00
mhajas 09348b2aff KEYCLOAK-5896 Run localization test only in community 2017-12-06 10:09:46 +01:00
mhajas 896e216f99 KEYCLOAK-5986 Fix token javacsript tests 2017-12-06 10:08:32 +01:00
stianst 35e60e0aa4 KEYCLOAK-5957 2017-12-06 08:59:40 +01:00
stianst 6d1c33ccdc KEYCLOAK-5667 2017-12-06 06:45:23 +01:00
Bill Burke f669fdf0df Merge pull request #4797 from stianst/KEYCLOAK-5734
KEYCLOAK-5734
2017-12-05 17:31:36 -05:00
Stan Silvert 30ad2899b8 KEYCLOAK-5933: Configure TOTP to Configure OTP 2017-12-05 17:24:54 -05:00
stianst 94ce97b972 KEYCLOAK-5734 2017-12-05 21:22:47 +01:00
Tomas Kyjovsky 3a7fd9e732 KEYCLOAK-5980 Dataset properties not loaded properly before test run - fix 2017-12-05 20:56:31 +01:00
Tomas Kyjovsky 503ad712dc KEYCLOAK-5955 Add ability to remotely monitor Infinispan and load balancer 2017-12-05 13:36:23 +01:00
mposolda f9e40326c1 KEYCLOAK-5961 Remove CrossDataCenter README file from codebase 2017-12-05 12:15:36 +01:00
mhajas 76029c7006 KEYCLOAK-4995 Fix Cluster tests on product and wildfly 10 2017-12-05 10:29:55 +01:00
James Stapleton 92cce7a6d4 [KEYCLOAK-5912] Add better improper SAML assertion error handling 2017-12-05 09:48:48 +01:00
Tomas Kyjovsky 916ba573bc KEYCLOAK-5965 fix 2017-12-05 09:21:56 +01:00
mposolda 6c34b4c418 KEYCLOAK-5914 Periodic clean of detached client sessions 2017-12-05 08:25:30 +01:00
stianst 5467d67c91 KEYCLOAK-5945 Strip default ports from urls 2017-12-04 19:56:01 +01:00
stianst c3d9f4704e KEYCLOAK-5946 Make sure wildcard origin is never returned 2017-12-04 19:55:34 +01:00
stianst 4541acc628 KEYCLOAK-5176 Strip headers from PEM when uploading to client 2017-12-04 19:54:15 +01:00
Stan Silvert 19cfbbf7ff KEYCLOAK-5972: i18n broken on keycloak-preview acct mgt 2017-12-04 13:44:16 -05:00
mposolda ff6fcd30d9 KEYCLOAK-4478 OIDC auth response lacks session_state in some cases 2017-12-04 16:13:22 +01:00
Samuel Mendenhall d69fe27cf9 set error instead of throw 2017-12-04 16:03:47 +01:00
Samuel Mendenhall ca324c29e8 processInit should return a promise for setupCheckLoginIframe and should only call processCallback if that setupCheckLoginIframe is successful 2017-12-04 16:03:47 +01:00
Hynek Mlnarik b4532ec629 KEYCLOAK-5964 Fix keycloak-install-base.cli client session caches 2017-12-04 12:15:07 +01:00
stianst 3ee269da87 Align dependencies 2017-12-04 10:14:30 +01:00
pedroigor b1127ffafe [KEYCLOAK-5953] - Making elytron dependencies optional 2017-12-04 10:13:55 +01:00
stianst 37de8e9f69 Bump version to 3.4.2.Final-SNAPSHOT 2017-12-01 09:34:48 +01:00
Stan Silvert 4d4ee33d1d KEYCLOAK-5937: Not possible to select role w/ hardocded LDAP role mapper 2017-11-30 15:29:36 -05:00
4096 changed files with 1263517 additions and 28579 deletions

No files matched your search

+10
View File
@@ -22,6 +22,16 @@ jdk:
install: true
before_install:
- "export PHANTOMJS_VERSION=2.1.1"
- "phantomjs --version"
- "export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH"
- "phantomjs --version"
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2; fi"
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi"
- "phantomjs --version"
script:
- ./travis-run-tests.sh $TESTS
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -206,6 +206,16 @@ public class AdapterDeploymentContext {
public void setBearerOnly(boolean bearerOnly) {
delegate.setBearerOnly(bearerOnly);
}
@Override
public boolean isAutodetectBearerOnly() {
return delegate.isAutodetectBearerOnly();
}
@Override
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
delegate.setAutodetectBearerOnly(autodetectBearerOnly);
}
@Override
public boolean isEnableBasicAuth() {
@@ -174,6 +174,10 @@ public class BearerTokenRequestAuthenticator {
@Override
public boolean challenge(HttpFacade facade) {
if (deployment.getPolicyEnforcer() != null) {
deployment.getPolicyEnforcer().enforce(OIDCHttpFacade.class.cast(facade));
return true;
}
OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description);
facade.getRequest().setError(error);
facade.getResponse().addHeader("WWW-Authenticate", challenge);
@@ -57,6 +57,8 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
/**
* Abstraction for creating HttpClients. Allows SSL configuration.
@@ -289,6 +291,7 @@ public class HttpClientBuilder {
cm = new SingleClientConnManager(registry);
}
BasicHttpParams params = new BasicHttpParams();
params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
if (proxyHost != null) {
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
@@ -154,6 +154,8 @@ public class KeycloakDeployment {
log.debug("resolveUrls");
}
authServerBaseUrl = authUrlBuilder.build().toString();
String login = authUrlBuilder.clone().path(ServiceUrlConstants.AUTH_PATH).build(getRealm()).toString();
authUrl = KeycloakUriBuilder.fromUri(login);
realmInfoUrl = authUrlBuilder.clone().path(ServiceUrlConstants.REALM_INFO_PATH).build(getRealm()).toString();
@@ -390,7 +390,8 @@ public class OAuthRequestAuthenticator {
protected String stripOauthParametersFromRedirect() {
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(facade.getRequest().getURI())
.replaceQueryParam(OAuth2Constants.CODE, null)
.replaceQueryParam(OAuth2Constants.STATE, null);
.replaceQueryParam(OAuth2Constants.STATE, null)
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null);
return builder.build().toString();
}
@@ -0,0 +1,97 @@
package org.keycloak.adapters.authentication;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.jboss.logging.Logger;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.common.util.Time;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.JsonWebToken;
/**
* Client authentication based on JWT signed by client secret instead of private key .
* See <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">specs</a> for more details.
*
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
*/
public class JWTClientSecretCredentialsProvider implements ClientCredentialsProvider {
private static final Logger logger = Logger.getLogger(JWTClientSecretCredentialsProvider.class);
public static final String PROVIDER_ID = "secret-jwt";
private SecretKey clientSecret;
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public void init(KeycloakDeployment deployment, Object config) {
if (config == null || !(config instanceof Map)) {
throw new RuntimeException("Configuration of jwt credentials by client secret is missing or incorrect for client '" + deployment.getResourceName() + "'. Check your adapter configuration");
}
Map<String, Object> cfg = (Map<String, Object>) config;
String clientSecretString = (String) cfg.get("secret");
if (clientSecretString == null) {
throw new RuntimeException("Missing parameter secret-jwt in configuration of jwt for client " + deployment.getResourceName());
}
setClientSecret(clientSecretString);
}
@Override
public void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formParams) {
String signedToken = createSignedRequestToken(deployment.getResourceName(), deployment.getRealmInfoUrl());
formParams.put(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT);
formParams.put(OAuth2Constants.CLIENT_ASSERTION, signedToken);
}
public void setClientSecret(String clientSecretString) {
// Get client secret and validate signature
// According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
// The HMAC (Hash-based Message Authentication Code) is calculated using the octets of the UTF-8 representation of the client_secret as the shared key.
// Use "HmacSHA256" consulting <a href="https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Mac.html">java8 api</a>
// because it must be implemented in every java platform.
try {
clientSecret = new SecretKeySpec(clientSecretString.getBytes("UTF-8"), "HmacSHA256");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Failed to create secret key spec due to unsupported encoding.");
}
}
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
// JOSE header {"alg":"HS256","typ" : "JWT"} no need "kid" due to using only one registered client secret.
// Use "HmacSHA256" consulting <a href="https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Mac.html">java8 api</a>.
// because it must be implemented in every java platform.
return new JWSBuilder().jsonContent(jwt).hmac256(clientSecret);
}
private JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
// According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
// JWT claims is the same as one by private_key_jwt
JsonWebToken reqToken = new JsonWebToken();
reqToken.id(AdapterUtils.generateId());
reqToken.issuer(clientId);
reqToken.subject(clientId);
reqToken.audience(realmInfoUrl);
int now = Time.currentTime();
reqToken.issuedAt(now);
// the same as in KEYCLOAK-2986, JWTClientCredentialsProvider's timeout field
reqToken.expiration(now + 10);
reqToken.notBefore(now);
return reqToken;
}
}
@@ -18,7 +18,6 @@
package org.keycloak.adapters.authorization;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -65,54 +64,58 @@ public abstract class AbstractPolicyEnforcer {
return createEmptyAuthorizationContext(true);
}
Request request = httpFacade.getRequest();
String path = getPath(request);
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
if (securityContext != null) {
AccessToken accessToken = securityContext.getToken();
if (securityContext == null) {
if (pathConfig != null) {
challenge(pathConfig, getRequiredScopes(pathConfig, request), httpFacade);
}
return createEmptyAuthorizationContext(false);
}
if (accessToken != null) {
Request request = httpFacade.getRequest();
String path = getPath(request);
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
AccessToken accessToken = securityContext.getToken();
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
if (accessToken != null) {
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken, null);
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
return createAuthorizationContext(accessToken, null);
}
handleAccessDenied(httpFacade);
return createEmptyAuthorizationContext(false);
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken, null);
}
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
return createEmptyAuthorizationContext(true);
LOGGER.debugf("Could not find a configuration for path [%s]", path);
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
return createAuthorizationContext(accessToken, null);
}
MethodConfig methodConfig = getRequiredScopes(pathConfig, request);
handleAccessDenied(httpFacade);
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken, pathConfig);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
}
return createEmptyAuthorizationContext(false);
}
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
return createEmptyAuthorizationContext(true);
}
MethodConfig methodConfig = getRequiredScopes(pathConfig, request);
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken, pathConfig);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
}
}
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
if (!challenge(pathConfig, methodConfig, httpFacade)) {
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
handleAccessDenied(httpFacade);
}
if (!challenge(pathConfig, methodConfig, httpFacade)) {
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
handleAccessDenied(httpFacade);
}
}
@@ -139,7 +142,7 @@ public abstract class AbstractPolicyEnforcer {
boolean hasPermission = false;
for (Permission permission : permissions) {
if (permission.getResourceSetId() != null) {
if (permission.getResourceId() != null) {
if (isResourcePermission(actualPathConfig, permission)) {
hasPermission = true;
@@ -292,6 +295,6 @@ public abstract class AbstractPolicyEnforcer {
}
private boolean matchResourcePermission(PathConfig actualPathConfig, Permission permission) {
return permission.getResourceSetId().equals(actualPathConfig.getId());
return permission.getResourceId().equals(actualPathConfig.getId());
}
}
@@ -23,11 +23,11 @@ import org.jboss.logging.Logger;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.PermissionRequest;
import org.keycloak.authorization.client.resource.PermissionResource;
import org.keycloak.authorization.client.resource.ProtectionResource;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.authorization.PermissionRequest;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -42,45 +42,40 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
@Override
protected boolean challenge(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
challengeUmaAuthentication(pathConfig, methodConfig, facade);
} else {
challengeEntitlementAuthentication(facade);
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String ticket = getPermissionTicket(pathConfig, methodConfig, authzClient);
if (ticket == null) {
response.setStatus(403);
return true;
}
String realm = authzClient.getConfiguration().getRealm();
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString();
response.setStatus(401);
StringBuilder wwwAuthenticate = new StringBuilder("UMA realm=\"").append(realm).append("\"").append(",as_uri=\"").append(authorizationServerUri).append("\"");
if (ticket != null) {
wwwAuthenticate.append(",ticket=\"").append(ticket).append("\"");
}
response.setHeader("WWW-Authenticate", wwwAuthenticate.toString());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending UMA challenge");
}
return true;
}
private void challengeEntitlementAuthentication(OIDCHttpFacade facade) {
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String clientId = authzClient.getConfiguration().getResource();
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending Entitlement challenge");
}
}
private void challengeUmaAuthentication(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String ticket = getPermissionTicket(pathConfig, methodConfig, authzClient);
String clientId = authzClient.getConfiguration().getResource();
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending UMA challenge");
}
}
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient) {
ProtectionResource protection = authzClient.protection();
PermissionResource permission = protection.permission();
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setResourceSetId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
return permission.forResource(permissionRequest).getTicket();
if (getEnforcerConfig().getUserManagedAccess() != null) {
ProtectionResource protection = authzClient.protection();
PermissionResource permission = protection.permission();
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setResourceId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
return permission.create(permissionRequest).getTicket();
}
return null;
}
}
@@ -19,25 +19,23 @@ package org.keycloak.adapters.authorization;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.authorization.client.AuthorizationDeniedException;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.AuthorizationRequest;
import org.keycloak.authorization.client.representation.AuthorizationResponse;
import org.keycloak.authorization.client.representation.EntitlementRequest;
import org.keycloak.authorization.client.representation.EntitlementResponse;
import org.keycloak.authorization.client.representation.PermissionRequest;
import org.keycloak.authorization.client.representation.PermissionResponse;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
import org.keycloak.representations.idm.authorization.Permission;
import org.keycloak.representations.idm.authorization.PermissionRequest;
import org.keycloak.representations.idm.authorization.PermissionResponse;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -90,6 +88,12 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
@Override
protected void handleAccessDenied(OIDCHttpFacade facade) {
KeycloakSecurityContext securityContext = facade.getSecurityContext();
if (securityContext == null) {
return;
}
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
HttpFacade.Response response = facade.getResponse();
@@ -103,45 +107,41 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
try {
String accessToken = httpFacade.getSecurityContext().getTokenString();
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
String accessTokenString = securityContext.getTokenString();
AuthzClient authzClient = getAuthzClient();
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setResourceId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
AccessToken accessToken = securityContext.getToken();
AuthorizationRequest authzRequest;
if (getEnforcerConfig().getUserManagedAccess() != null) {
LOGGER.debug("Obtaining authorization for authenticated user.");
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setResourceSetId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
PermissionResponse permissionResponse = authzClient.protection().permission().forResource(permissionRequest);
AuthorizationRequest authzRequest = new AuthorizationRequest(permissionResponse.getTicket());
AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
if (authzResponse != null) {
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
}
return null;
PermissionResponse permissionResponse = authzClient.protection().permission().create(permissionRequest);
authzRequest = new AuthorizationRequest();
authzRequest.setTicket(permissionResponse.getTicket());
} else {
LOGGER.debug("Obtaining entitlements for authenticated user.");
AccessToken token = httpFacade.getSecurityContext().getToken();
if (token.getAuthorization() == null) {
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getResource());
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
} else {
EntitlementRequest request = new EntitlementRequest();
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setResourceSetId(pathConfig.getId());
permissionRequest.setResourceSetName(pathConfig.getName());
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
LOGGER.debugf("Sending entitlements request: resource_set_id [%s], resource_set_name [%s], scopes [%s].", permissionRequest.getResourceSetId(), permissionRequest.getResourceSetName(), permissionRequest.getScopes());
request.addPermission(permissionRequest);
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getResource(), request);
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
authzRequest = new AuthorizationRequest();
if (accessToken.getAuthorization() != null) {
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
}
}
if (accessToken.getAuthorization() != null) {
authzRequest.setRpt(accessTokenString);
}
LOGGER.debug("Obtaining authorization for authenticated user.");
AuthorizationResponse authzResponse = authzClient.authorization(accessTokenString).authorize(authzRequest);
if (authzResponse != null) {
return AdapterRSATokenVerifier.verifyToken(authzResponse.getToken(), deployment);
}
return null;
} catch (AuthorizationDeniedException e) {
LOGGER.debug("Authorization denied", e);
return null;
@@ -18,8 +18,8 @@
package org.keycloak.adapters.authorization;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
@@ -95,7 +95,9 @@ class PathMatcher {
}
if (WILDCARD == expectedUri.charAt(expectedUri.length() - 1)) {
matchingAnyPath = entry;
if (matchingAnyPath == null || matchingAnyPath.getPath().length() < matchingUri.length()) {
matchingAnyPath = entry;
}
} else {
int suffixIndex = expectedUri.indexOf(WILDCARD + ".");
@@ -221,11 +223,11 @@ class PathMatcher {
private PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
if (originalConfig.hasPattern()) {
ProtectedResource resource = this.authzClient.protection().resource();
Set<String> search = resource.findByFilter("uri=" + path);
List<ResourceRepresentation> search = resource.findByUri(path);
if (!search.isEmpty()) {
// resource does exist on the server, cache it
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
ResourceRepresentation targetResource = search.get(0);
PathConfig config = PolicyEnforcer.createPathConfig(targetResource);
config.setScopes(originalConfig.getScopes());
@@ -17,6 +17,15 @@
*/
package org.keycloak.adapters.authorization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.adapters.KeycloakDeployment;
@@ -25,7 +34,6 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthenticator;
import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.RegistrationResponse;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.representation.ScopeRepresentation;
import org.keycloak.authorization.client.resource.ProtectedResource;
@@ -34,14 +42,6 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.authorization.Permission;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@@ -58,10 +58,15 @@ public class PolicyEnforcer {
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
this.deployment = deployment;
this.enforcerConfig = adapterConfig.getPolicyEnforcerConfig();
this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()), new ClientAuthenticator() {
Configuration configuration = new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient());
this.authzClient = AuthzClient.create(configuration, new ClientAuthenticator() {
@Override
public void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders) {
ClientCredentialsProviderUtils.setClientCredentials(PolicyEnforcer.this.deployment, requestHeaders, requestParams);
public void configureClientCredentials(Map<String, List<String>> requestParams, Map<String, String> requestHeaders) {
Map<String, String> formparams = new HashMap<>();
ClientCredentialsProviderUtils.setClientCredentials(PolicyEnforcer.this.deployment, requestHeaders, formparams);
for (Entry<String, String> param : formparams.entrySet()) {
requestParams.put(param.getKey(), Arrays.asList(param.getValue()));
}
}
});
this.pathMatcher = new PathMatcher(this.authzClient);
@@ -142,26 +147,34 @@ public class PolicyEnforcer {
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
Set<String> search;
ResourceRepresentation resource;
String resourceName = pathConfig.getName();
String path = pathConfig.getPath();
if (resourceName != null) {
LOGGER.debugf("Trying to find resource with name [%s] for path [%s].", resourceName, path);
search = protectedResource.findByFilter("name=" + resourceName);
resource = protectedResource.findByName(resourceName);
} else {
LOGGER.debugf("Trying to find resource with uri [%s] for path [%s].", path, path);
search = protectedResource.findByFilter("uri=" + path);
List<ResourceRepresentation> resources = protectedResource.findByUri(path);
if (resources.size() == 1) {
resource = resources.get(0);
} else if (resources.size() > 1) {
throw new RuntimeException("Multiple resources found with the same uri");
} else {
resource = null;
}
}
if (search.isEmpty()) {
if (resource == null) {
if (enforcerConfig.isCreateResources()) {
LOGGER.debugf("Creating resource on server for path [%s].", pathConfig);
ResourceRepresentation resource = new ResourceRepresentation();
ResourceRepresentation representation = new ResourceRepresentation();
resource.setName(resourceName);
resource.setType(pathConfig.getType());
resource.setUri(path);
representation.setName(resourceName);
representation.setType(pathConfig.getType());
representation.setUri(path);
HashSet<ScopeRepresentation> scopes = new HashSet<>();
@@ -173,16 +186,16 @@ public class PolicyEnforcer {
scopes.add(scope);
}
resource.setScopes(scopes);
representation.setScopes(scopes);
RegistrationResponse registrationResponse = protectedResource.create(resource);
ResourceRepresentation registrationResponse = protectedResource.create(representation);
pathConfig.setId(registrationResponse.getId());
} else {
throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + "]. Make sure you have created a resource on the server that matches with the path configuration.");
}
} else {
pathConfig.setId(search.iterator().next());
pathConfig.setId(resource.getId());
}
PathConfig existingPath = null;
@@ -210,8 +223,7 @@ public class PolicyEnforcer {
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
for (String id : protectedResource.findAll()) {
RegistrationResponse response = protectedResource.findById(id);
ResourceRepresentation resourceDescription = response.getResourceDescription();
ResourceRepresentation resourceDescription = protectedResource.findById(id);
if (resourceDescription.getUri() != null) {
PathConfig pathConfig = createPathConfig(resourceDescription);
@@ -16,4 +16,5 @@
#
org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider
org.keycloak.adapters.authentication.JWTClientCredentialsProvider
org.keycloak.adapters.authentication.JWTClientCredentialsProvider
org.keycloak.adapters.authentication.JWTClientSecretCredentialsProvider
@@ -21,6 +21,7 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.junit.Test;
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
import org.keycloak.adapters.authentication.JWTClientSecretCredentialsProvider;
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
import org.keycloak.common.enums.RelativeUrlsUsed;
@@ -94,4 +95,9 @@ public class KeycloakDeploymentBuilderTest {
assertEquals(JWTClientCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
}
@Test
public void loadSecretJwtCredentials() throws Exception {
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-secret-jwt.json"));
assertEquals(JWTClientSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
}
}
@@ -17,7 +17,9 @@
package org.keycloak.adapters;
import org.junit.Test;
import org.keycloak.representations.adapters.config.AdapterConfig;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -46,4 +48,21 @@ public class KeycloakDeploymentTest {
assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled());
}
@Test
public void stripDefaultPorts() {
KeycloakDeployment keycloakDeployment = new KeycloakDeployment();
keycloakDeployment.setRealm("test");
AdapterConfig config = new AdapterConfig();
config.setAuthServerUrl("http://localhost:80/auth");
keycloakDeployment.setAuthServerBaseUrl(config);
assertEquals("http://localhost/auth", keycloakDeployment.getAuthServerBaseUrl());
config.setAuthServerUrl("https://localhost:443/auth");
keycloakDeployment.setAuthServerBaseUrl(config);
assertEquals("https://localhost/auth", keycloakDeployment.getAuthServerBaseUrl());
}
}
@@ -0,0 +1,12 @@
{
"realm": "demo",
"resource": "customer-portal",
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "https://localhost:8443/auth",
"ssl-required": "external",
"credentials": {
"secret-jwt": {
"secret": "234234-234234-234234"
}
}
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+10 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -63,6 +63,15 @@
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
</dependency>
</dependencies>
<build>
@@ -53,7 +53,13 @@ public class KeycloakCliSso {
login();
} else if (args[0].equalsIgnoreCase("login-manual")) {
loginManual();
} else if (args[0].equalsIgnoreCase("token")) {
}
/*
else if (args[0].equalsIgnoreCase("login-cli")) {
loginCli();
}
*/
else if (args[0].equalsIgnoreCase("token")) {
token();
} else if (args[0].equalsIgnoreCase("logout")) {
logout();
@@ -69,6 +75,7 @@ public class KeycloakCliSso {
System.err.println("Commands:");
System.err.println(" login - login with desktop browser if available, otherwise do manual login. Output is access token.");
System.err.println(" login-manual - manual login");
//System.err.println(" login-cli - attempt Keycloak proprietary cli protocol. Otherwise do normal login");
System.err.println(" token - print access token if logged in");
System.err.println(" logout - logout.");
System.exit(1);
@@ -110,7 +117,7 @@ public class KeycloakCliSso {
return config;
}
public boolean checkToken() throws Exception {
public boolean checkToken(boolean outputToken) throws Exception {
String token = getTokenResponse();
if (token == null) return false;
@@ -127,7 +134,7 @@ public class KeycloakCliSso {
AdapterConfig config = getConfig();
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
installed.refreshToken(tokenResponse.getRefreshToken());
processResponse(installed);
processResponse(installed, outputToken);
return true;
} catch (Exception e) {
System.err.println("Error processing existing token");
@@ -184,11 +191,19 @@ public class KeycloakCliSso {
}
public void login() throws Exception {
if (checkToken()) return;
if (checkToken(true)) return;
AdapterConfig config = getConfig();
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
installed.login();
processResponse(installed);
processResponse(installed, true);
}
public void loginCli() throws Exception {
if (checkToken(false)) return;
AdapterConfig config = getConfig();
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
if (!installed.loginCommandLine()) installed.login();
processResponse(installed, false);
}
public String getHome() {
@@ -210,7 +225,7 @@ public class KeycloakCliSso {
return Paths.get(getHome(), System.getProperty("basepath", ".keycloak-sso"), System.getProperty("KEYCLOAK_REALM"), System.getProperty("KEYCLOAK_CLIENT") + ".json").toFile();
}
private void processResponse(KeycloakInstalled installed) throws IOException {
private void processResponse(KeycloakInstalled installed, boolean outputToken) throws IOException {
AccessTokenResponse tokenResponse = installed.getTokenResponse();
tokenResponse.setExpiresIn(Time.currentTime() + tokenResponse.getExpiresIn());
tokenResponse.setIdToken(null);
@@ -220,16 +235,16 @@ public class KeycloakCliSso {
fos.write(output.getBytes("UTF-8"));
fos.flush();
fos.close();
System.out.println(tokenResponse.getToken());
if (outputToken) System.out.println(tokenResponse.getToken());
}
public void loginManual() throws Exception {
if (checkToken()) return;
if (checkToken(true)) return;
AdapterConfig config = getConfig();
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(config);
KeycloakInstalled installed = new KeycloakInstalled(deployment);
installed.loginManual();
processResponse(installed);
processResponse(installed, true);
}
public void logout() throws Exception {
@@ -17,7 +17,8 @@
package org.keycloak.adapters.installed;
import org.apache.commons.codec.Charsets;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.adapters.KeycloakDeployment;
@@ -32,6 +33,11 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.IDToken;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
@@ -40,6 +46,7 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
@@ -48,6 +55,8 @@ import java.net.URISyntaxException;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -77,6 +86,9 @@ public class KeycloakInstalled {
private Locale locale;
private HttpResponseWriter loginResponseWriter;
private HttpResponseWriter logoutResponseWriter;
Pattern callbackPattern = Pattern.compile("callback\\s*=\\s*\"([^\"]+)\"");
Pattern paramPattern = Pattern.compile("param=\"([^\"]+)\"\\s+label=\"([^\"]+)\"\\s+mask=(\\S+)");
Pattern codePattern = Pattern.compile("code=([^&]+)");
@@ -290,6 +302,86 @@ public class KeycloakInstalled {
status = Status.LOGGED_MANUAL;
}
public boolean loginCommandLine() throws IOException, ServerRequest.HttpFailure, VerificationException {
String redirectUri = "urn:ietf:wg:oauth:2.0:oob";
return loginCommandLine(redirectUri);
}
/**
* Experimental proprietary WWW-Authentication challenge protocol.
* WWW-Authentication: X-Text-Form-Challenge callback="{url}" param="{param-name}" label="{param-display-label}"
*
* @param redirectUri
* @return
* @throws IOException
* @throws ServerRequest.HttpFailure
* @throws VerificationException
*/
public boolean loginCommandLine(String redirectUri) throws IOException, ServerRequest.HttpFailure, VerificationException {
String authUrl = deployment.getAuthUrl().clone()
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)
.build().toString();
ResteasyClient client = new ResteasyClientBuilder().disableTrustManager().build();
try {
Response response = client.target(authUrl).request().get();
if (response.getStatus() != 401) {
return false;
}
while (true) {
String authenticationHeader = response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE);
if (authenticationHeader == null) {
return false;
}
if (!authenticationHeader.contains("X-Text-Form-Challenge")) {
return false;
}
if (response.getMediaType() != null) {
String splash = response.readEntity(String.class);
System.console().writer().println(splash);
}
Matcher m = callbackPattern.matcher(authenticationHeader);
if (!m.find()) return false;
String callback = m.group(1);
//System.err.println("callback: " + callback);
m = paramPattern.matcher(authenticationHeader);
Form form = new Form();
while (m.find()) {
String param = m.group(1);
String label = m.group(2);
String mask = m.group(3).trim();
boolean maskInput = mask.equals("true");
String value = null;
if (maskInput) {
char[] txt = System.console().readPassword(label);
value = new String(txt);
} else {
value = System.console().readLine(label);
}
form.param(param, value);
}
response = client.target(callback).request().post(Entity.form(form));
if (response.getStatus() == 401) continue;
if (response.getStatus() != 302) return false;
String location = response.getLocation().toString();
m = codePattern.matcher(location);
if (!m.find()) return false;
String code = m.group(1);
processCode(code, redirectUri);
return true;
}
} finally {
client.close();
}
}
public String getTokenString() throws VerificationException, IOException, ServerRequest.HttpFailure {
return tokenString;
}
@@ -382,6 +474,86 @@ public class KeycloakInstalled {
return sb.toString();
}
public static class MaskingThread extends Thread {
private volatile boolean stop;
private char echochar = '*';
public MaskingThread() {
}
/**
* Begin masking until asked to stop.
*/
public void run() {
int priority = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try {
stop = true;
while(stop) {
System.out.print("\010" + echochar);
try {
// attempt masking at this rate
Thread.currentThread().sleep(1);
}catch (InterruptedException iex) {
Thread.currentThread().interrupt();
return;
}
}
} finally { // restore the original priority
Thread.currentThread().setPriority(priority);
}
}
/**
* Instruct the thread to stop masking.
*/
public void stopMasking() {
this.stop = false;
}
}
public static String readMasked(Reader reader) {
MaskingThread et = new MaskingThread();
Thread mask = new Thread(et);
mask.start();
BufferedReader in = new BufferedReader(reader);
String password = "";
try {
password = in.readLine();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// stop masking
et.stopMasking();
// return the password entered by the user
return password;
}
private String readLine(Reader reader, boolean mask) throws IOException {
if (mask) {
System.out.print(" ");
return readMasked(reader);
}
StringBuilder sb = new StringBuilder();
char cb[] = new char[1];
while (reader.read(cb) != -1) {
char c = cb[0];
if ((c == '\n') || (c == '\r')) {
break;
} else {
sb.append(c);
}
}
return sb.toString();
}
public class CallbackListener extends Thread {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+2 -2
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
@@ -33,6 +33,7 @@
<modules>
<module>jetty-core</module>
<module>jetty8.1</module>
<module>jetty9.1</module>
<module>jetty9.2</module>
<module>jetty9.3</module>
</modules>
@@ -46,7 +47,6 @@
</property>
</activation>
<modules>
<module>jetty9.1</module>
<module>jetty9.4</module>
</modules>
</profile>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -18,14 +18,14 @@
(function( window, undefined ) {
var KeycloakAuthorization = function (keycloak) {
var KeycloakAuthorization = function (keycloak, options) {
var _instance = this;
this.rpt = null;
this.init = function () {
var request = new XMLHttpRequest();
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma-configuration');
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma2-configuration');
request.onreadystatechange = function () {
if (request.readyState == 4) {
if (request.status == 200) {
@@ -47,68 +47,61 @@
* necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
* depending on how the policy enforcer at the resource server was configured.
*/
this.authorize = function (wwwAuthenticateHeader) {
this.authorize = function (authorizationRequest) {
this.then = function (onGrant, onDeny, onError) {
if (wwwAuthenticateHeader.indexOf('UMA') != -1) {
var params = wwwAuthenticateHeader.split(',');
if (authorizationRequest && authorizationRequest.ticket) {
var request = new XMLHttpRequest();
for (i = 0; i < params.length; i++) {
var param = params[i].split('=');
request.open('POST', _instance.config.token_endpoint, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
if (param[0] == 'ticket') {
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4) {
var status = request.status;
request.open('POST', _instance.config.rpt_endpoint, true);
request.setRequestHeader('Content-Type', 'application/json')
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.onreadystatechange = function () {
if (request.readyState == 4) {
var status = request.status;
if (status >= 200 && status < 300) {
var rpt = JSON.parse(request.responseText).rpt;
_instance.rpt = rpt;
onGrant(rpt);
} else if (status == 403) {
if (onDeny) {
onDeny();
} else {
console.error('Authorization request was denied by the server.');
}
} else {
if (onError) {
onError();
} else {
console.error('Could not obtain authorization data from server.');
}
}
if (status >= 200 && status < 300) {
var rpt = JSON.parse(request.responseText).access_token;
_instance.rpt = rpt;
onGrant(rpt);
} else if (status == 403) {
if (onDeny) {
onDeny();
} else {
console.error('Authorization request was denied by the server.');
}
};
var ticket = param[1].substring(1, param[1].length - 1).trim();
request.send(JSON.stringify(
{
ticket: ticket,
rpt: _instance.rpt
} else {
if (onError) {
onError();
} else {
console.error('Could not obtain authorization data from server.');
}
));
}
}
};
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId + "&ticket=" + authorizationRequest.ticket;
if (authorizationRequest.submitRequest != undefined) {
params += "&submit_request=" + authorizationRequest.submitRequest;
}
} else if (wwwAuthenticateHeader.indexOf('KC_ETT') != -1) {
var params = wwwAuthenticateHeader.substring('KC_ETT'.length).trim().split(',');
var clientId = null;
for (i = 0; i < params.length; i++) {
var param = params[i].split('=');
var metadata = authorizationRequest.metadata;
if (param[0] == 'realm') {
clientId = param[1].substring(1, param[1].length - 1).trim();
if (metadata) {
if (metadata.responseIncludeResourceName) {
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
}
if (metadata.responsePermissionsLimit) {
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
}
}
_instance.entitlement(clientId).then(onGrant, onDeny, onError);
if (_instance.rpt && (authorizationRequest.incrementalAuthorization == undefined || authorizationRequest.incrementalAuthorization)) {
params += "&rpt=" + _instance.rpt;
}
request.send(params);
}
};
@@ -116,20 +109,22 @@
};
/**
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
* Obtains all entitlements from a Keycloak Server based on a given resourceServerId.
*/
this.entitlement = function (resourceSeververId, entitlementRequest ) {
this.entitlement = function (resourceServerId, authorizationRequest) {
this.then = function (onGrant, onDeny, onError) {
var request = new XMLHttpRequest();
request.open('POST', _instance.config.token_endpoint, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
request.onreadystatechange = function () {
if (request.readyState == 4) {
var status = request.status;
if (status >= 200 && status < 300) {
var rpt = JSON.parse(request.responseText).rpt;
var rpt = JSON.parse(request.responseText).access_token;
_instance.rpt = rpt;
onGrant(rpt);
} else if (status == 403) {
@@ -148,19 +143,62 @@
}
};
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);
if (!authorizationRequest) {
authorizationRequest = {};
}
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.send(erJson);
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId;
if (authorizationRequest.claimToken) {
params += "&claim_token=" + authorizationRequest.claimToken;
if (authorizationRequest.claimTokenFormat) {
params += "&claim_token_format=" + authorizationRequest.claimTokenFormat;
}
}
params += "&audience=" + resourceServerId;
var permissions = authorizationRequest.permissions;
if (!permissions) {
permissions = [];
}
for (i = 0; i < permissions.length; i++) {
var resource = permissions[i];
var permission = resource.id;
if (resource.scopes && resource.scopes.length > 0) {
permission += "#";
for (j = 0; j < resource.scopes.length; j++) {
var scope = resource.scopes[j];
if (permission.indexOf('#') != permission.length - 1) {
permission += ",";
}
permission += scope;
}
}
params += "&permission=" + permission;
}
var metadata = authorizationRequest.metadata;
if (metadata) {
if (metadata.responseIncludeResourceName) {
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
}
if (metadata.responsePermissionsLimit) {
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
}
}
if (_instance.rpt) {
params += "&rpt=" + _instance.rpt;
}
request.send(params);
};
return this;
+7 -2
View File
@@ -39,8 +39,13 @@ declare namespace Keycloak {
/**
* @private Undocumented.
*/
adapter?: KeycloakAdapterName;
useNonce?: boolean;
/**
* @private Undocumented.
*/
adapter?: KeycloakAdapterName;
/**
* Specifies an action to do on load.
*/
@@ -78,7 +83,7 @@ declare namespace Keycloak {
* Set the interval to check login state (in seconds).
* @default 5
*/
checkLoginIframeInterval?: boolean;
checkLoginIframeInterval?: number;
/**
* Set the OpenID Connect response mode to send to Keycloak upon login.
+289 -157
View File
@@ -40,6 +40,8 @@
}
}
var useNonce = true;
kc.init = function (initOptions) {
kc.authenticated = false;
@@ -58,6 +60,10 @@
}
if (initOptions) {
if (typeof initOptions.useNonce !== 'undefined') {
useNonce = initOptions.useNonce;
}
if (typeof initOptions.checkLoginIframe !== 'undefined') {
loginIframe.enable = initOptions.checkLoginIframe;
}
@@ -159,10 +165,15 @@
var callback = parseCallback(window.location.href);
if (callback) {
setupCheckLoginIframe();
window.history.replaceState({}, null, callback.newUrl);
processCallback(callback, initPromise);
return;
}
if (callback && callback.valid) {
return setupCheckLoginIframe().success(function() {
processCallback(callback, initPromise);
}).error(function (e) {
initPromise.setError();
});
} else if (initOptions) {
if (initOptions.token && initOptions.refreshToken) {
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
@@ -230,22 +241,25 @@
callbackStorage.add(callbackState);
var action = 'auth';
var baseUrl;
if (options && options.action == 'register') {
action = 'registrations';
baseUrl = kc.endpoints.register();
} else {
baseUrl = kc.endpoints.authorize();
}
var scope = (options && options.scope) ? "openid " + options.scope : "openid";
var url = getRealmUrl()
+ '/protocol/openid-connect/' + action
var url = baseUrl
+ '?client_id=' + encodeURIComponent(kc.clientId)
+ '&redirect_uri=' + encodeURIComponent(redirectUri)
+ '&state=' + encodeURIComponent(state)
+ '&nonce=' + encodeURIComponent(nonce)
+ '&response_mode=' + encodeURIComponent(kc.responseMode)
+ '&response_type=' + encodeURIComponent(kc.responseType)
+ '&scope=' + encodeURIComponent(scope);
if (useNonce) {
url = url + '&nonce=' + encodeURIComponent(nonce);
}
if (options && options.prompt) {
url += '&prompt=' + encodeURIComponent(options.prompt);
@@ -275,8 +289,7 @@
}
kc.createLogoutUrl = function(options) {
var url = getRealmUrl()
+ '/protocol/openid-connect/logout'
var url = kc.endpoints.logout()
+ '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
return url;
@@ -295,11 +308,14 @@
}
kc.createAccountUrl = function(options) {
var url = getRealmUrl()
var realm = getRealmUrl();
var url = undefined;
if (typeof realm !== 'undefined') {
url = realm
+ '/account'
+ '?referrer=' + encodeURIComponent(kc.clientId)
+ '&referrer_uri=' + encodeURIComponent(adapter.redirectUri(options));
}
return url;
}
@@ -347,7 +363,7 @@
}
kc.loadUserInfo = function() {
var url = getRealmUrl() + '/protocol/openid-connect/userinfo';
var url = kc.endpoints.userinfo();
var req = new XMLHttpRequest();
req.open('GET', url, true);
req.setRequestHeader('Accept', 'application/json');
@@ -412,7 +428,7 @@
promise.setSuccess(false);
} else {
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
var url = getRealmUrl() + '/protocol/openid-connect/token';
var url = kc.endpoints.token();
refreshQueue.push(promise);
@@ -486,10 +502,14 @@
}
function getRealmUrl() {
if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
if (typeof kc.authServerUrl !== 'undefined') {
if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
} else {
return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
}
} else {
return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
return undefined;
}
}
@@ -523,7 +543,7 @@
if ((kc.flow != 'implicit') && code) {
var params = 'code=' + code + '&grant_type=authorization_code';
var url = getRealmUrl() + '/protocol/openid-connect/token';
var url = kc.endpoints.token();
var req = new XMLHttpRequest();
req.open('POST', url, true);
@@ -560,9 +580,9 @@
setToken(accessToken, refreshToken, idToken, timeLocal);
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
if (useNonce && ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce))) {
console.info('[KEYCLOAK] Invalid nonce, clearing token');
kc.clearToken();
@@ -587,6 +607,65 @@
configUrl = config;
}
function setupOidcEndoints(oidcConfiguration) {
if (! oidcConfiguration) {
kc.endpoints = {
authorize: function() {
return getRealmUrl() + '/protocol/openid-connect/auth';
},
token: function() {
return getRealmUrl() + '/protocol/openid-connect/token';
},
logout: function() {
return getRealmUrl() + '/protocol/openid-connect/logout';
},
checkSessionIframe: function() {
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
if (kc.iframeVersion) {
src = src + '?version=' + kc.iframeVersion;
}
return src;
},
register: function() {
return getRealmUrl() + '/protocol/openid-connect/registrations';
},
userinfo: function() {
return getRealmUrl() + '/protocol/openid-connect/userinfo';
}
};
} else {
kc.endpoints = {
authorize: function() {
return oidcConfiguration.authorization_endpoint;
},
token: function() {
return oidcConfiguration.token_endpoint;
},
logout: function() {
if (!oidcConfiguration.end_session_endpoint) {
throw "Not supported by the OIDC server";
}
return oidcConfiguration.end_session_endpoint;
},
checkSessionIframe: function() {
if (!oidcConfiguration.check_session_iframe) {
throw "Not supported by the OIDC server";
}
return oidcConfiguration.check_session_iframe;
},
register: function() {
throw 'Redirection to "Register user" page not supported in standard OIDC mode';
},
userinfo: function() {
if (!oidcConfiguration.userinfo_endpoint) {
throw "Not supported by the OIDC server";
}
return oidcConfiguration.userinfo_endpoint;
}
}
}
}
if (configUrl) {
var req = new XMLHttpRequest();
req.open('GET', configUrl, true);
@@ -601,7 +680,7 @@
kc.realm = config['realm'];
kc.clientId = config['resource'];
kc.clientSecret = (config['credentials'] || {})['secret'];
setupOidcEndoints(null);
promise.setSuccess();
} else {
promise.setError();
@@ -611,30 +690,62 @@
req.send();
} else {
if (!config['url']) {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src.match(/.*keycloak\.js/)) {
config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
break;
}
}
}
if (!config.realm) {
throw 'realm missing';
}
if (!config.clientId) {
throw 'clientId missing';
}
kc.authServerUrl = config.url;
kc.realm = config.realm;
kc.clientId = config.clientId;
kc.clientSecret = (config.credentials || {}).secret;
promise.setSuccess();
var oidcProvider = config['oidcProvider'];
if (!oidcProvider) {
if (!config['url']) {
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if (scripts[i].src.match(/.*keycloak\.js/)) {
config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
break;
}
}
}
if (!config.realm) {
throw 'realm missing';
}
kc.authServerUrl = config.url;
kc.realm = config.realm;
setupOidcEndoints(null);
promise.setSuccess();
} else {
if (typeof oidcProvider === 'string') {
var oidcProviderConfigUrl;
if (oidcProvider.charAt(oidcProvider.length - 1) == '/') {
oidcProviderConfigUrl = oidcProvider + '.well-known/openid-configuration';
} else {
oidcProviderConfigUrl = oidcProvider + '/.well-known/openid-configuration';
}
var req = new XMLHttpRequest();
req.open('GET', oidcProviderConfigUrl, true);
req.setRequestHeader('Accept', 'application/json');
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200 || fileLoaded(req)) {
var oidcProviderConfig = JSON.parse(req.responseText);
setupOidcEndoints(oidcProviderConfig);
promise.setSuccess();
} else {
promise.setError();
}
}
};
req.send();
} else {
setupOidcEndoints(oidcProvider);
promise.setSuccess();
}
}
}
return promise.promise;
@@ -753,23 +864,137 @@
}
function parseCallback(url) {
var oauth = new CallbackParser(url, kc.responseMode).parseUri();
var oauth = parseCallbackUrl(url);
if (!oauth) {
return;
}
var oauthState = callbackStorage.get(oauth.state);
if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
if (oauthState) {
oauth.valid = true;
oauth.redirectUri = oauthState.redirectUri;
oauth.storedNonce = oauthState.nonce;
oauth.prompt = oauthState.prompt;
}
if (oauth.fragment) {
oauth.newUrl += '#' + oauth.fragment;
return oauth;
}
function parseCallbackUrl(url) {
var supportedParams;
switch (kc.flow) {
case 'standard':
supportedParams = ['code', 'state', 'session_state'];
break;
case 'implicit':
supportedParams = ['access_token', 'id_token', 'state', 'session_state'];
break;
case 'hybrid':
supportedParams = ['access_token', 'id_token', 'code', 'state', 'session_state'];
break;
}
supportedParams.push('error');
supportedParams.push('error_description');
supportedParams.push('error_uri');
var queryIndex = url.indexOf('?');
var fragmentIndex = url.indexOf('#');
var newUrl;
var parsed;
if (kc.responseMode === 'query' && queryIndex !== -1) {
newUrl = url.substring(0, queryIndex);
parsed = parseCallbackParams(url.substring(queryIndex + 1, fragmentIndex !== -1 ? fragmentIndex : url.length), supportedParams);
if (parsed.paramsString !== '') {
newUrl += '?' + parsed.paramsString;
}
if (fragmentIndex !== -1) {
newUrl += url.substring(fragmentIndex);
}
} else if (kc.responseMode === 'fragment' && fragmentIndex !== -1) {
newUrl = url.substring(0, fragmentIndex);
parsed = parseCallbackParams(url.substring(fragmentIndex + 1), supportedParams);
if (parsed.paramsString !== '') {
newUrl += '#' + parsed.paramsString;
}
}
return oauth;
if (parsed && parsed.oauthParams) {
if (kc.flow === 'standard' || kc.flow === 'hybrid') {
if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
parsed.oauthParams.newUrl = newUrl;
return parsed.oauthParams;
}
} else if (kc.flow === 'implicit') {
if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
parsed.oauthParams.newUrl = newUrl;
return parsed.oauthParams;
}
}
}
}
function parseCallbackParams(paramsString, supportedParams) {
var p = paramsString.split('&');
var result = {
paramsString: '',
oauthParams: {}
}
for (var i = 0; i < p.length; i++) {
var t = p[i].split('=');
if (supportedParams.indexOf(t[0]) !== -1) {
result.oauthParams[t[0]] = t[1];
} else {
if (result.paramsString !== '') {
result.paramsString += '&';
}
result.paramsString += p[i];
}
}
return result;
}
function createPromise() {
if (typeof Promise === "function") {
return createNativePromise();
} else {
return createLegacyPromise();
}
}
function createNativePromise() {
// Need to create a native Promise which also preserves the
// interface of the custom promise type previously used by the API
var p = {
setSuccess: function(result) {
p.success = true;
p.resolve(result);
},
setError: function(result) {
p.success = false;
p.reject(result);
}
};
p.promise = new Promise(function(resolve, reject) {
p.resolve = resolve;
p.reject = reject;
});
p.promise.success = function(callback) {
p.promise.then(callback);
return p.promise;
}
p.promise.error = function(callback) {
p.promise.catch(callback);
return p.promise;
}
return p;
}
function createLegacyPromise() {
var p = {
setSuccess: function(result) {
p.success = true;
@@ -826,22 +1051,18 @@
loginIframe.iframe = iframe;
iframe.onload = function() {
var realmUrl = getRealmUrl();
if (realmUrl.charAt(0) === '/') {
var authUrl = kc.endpoints.authorize();
if (authUrl.charAt(0) === '/') {
loginIframe.iframeOrigin = getOrigin();
} else {
loginIframe.iframeOrigin = realmUrl.substring(0, realmUrl.indexOf('/', 8));
loginIframe.iframeOrigin = authUrl.substring(0, authUrl.indexOf('/', 8));
}
promise.setSuccess();
setTimeout(check, loginIframe.interval * 1000);
}
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
if (kc.iframeVersion) {
src = src + '?version=' + kc.iframeVersion;
}
var src = kc.endpoints.checkSessionIframe();
iframe.setAttribute('src', src );
iframe.setAttribute('title', 'keycloak-session-iframe' );
iframe.style.display = 'none';
@@ -921,7 +1142,12 @@
},
accountManagement : function() {
window.location.href = kc.createAccountUrl();
var accountUrl = kc.createAccountUrl();
if (typeof accountUrl !== 'undefined') {
window.location.href = accountUrl;
} else {
throw "Not supported by the OIDC server";
}
return createPromise().promise;
},
@@ -935,12 +1161,7 @@
} else if (kc.redirectUri) {
return kc.redirectUri;
} else {
var redirectUri = location.href;
if (location.hash && encodeHash) {
redirectUri = redirectUri.substring(0, location.href.indexOf('#'));
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
}
return redirectUri;
return location.href;
}
}
};
@@ -1042,12 +1263,16 @@
accountManagement : function() {
var accountUrl = kc.createAccountUrl();
var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
ref.close();
}
});
if (typeof accountUrl !== 'undefined') {
var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
ref.close();
}
});
} else {
throw "Not supported by the OIDC server";
}
},
redirectUri: function(options) {
@@ -1177,99 +1402,6 @@
return new CookieStorage();
}
var CallbackParser = function(uriToParse, responseMode) {
if (!(this instanceof CallbackParser)) {
return new CallbackParser(uriToParse, responseMode);
}
var parser = this;
var initialParse = function() {
var baseUri = null;
var queryString = null;
var fragmentString = null;
var questionMarkIndex = uriToParse.indexOf("?");
var fragmentIndex = uriToParse.indexOf("#", questionMarkIndex + 1);
if (questionMarkIndex == -1 && fragmentIndex == -1) {
baseUri = uriToParse;
} else if (questionMarkIndex != -1) {
baseUri = uriToParse.substring(0, questionMarkIndex);
queryString = uriToParse.substring(questionMarkIndex + 1);
if (fragmentIndex != -1) {
fragmentIndex = queryString.indexOf("#");
fragmentString = queryString.substring(fragmentIndex + 1);
queryString = queryString.substring(0, fragmentIndex);
}
} else {
baseUri = uriToParse.substring(0, fragmentIndex);
fragmentString = uriToParse.substring(fragmentIndex + 1);
}
return { baseUri: baseUri, queryString: queryString, fragmentString: fragmentString };
}
var parseParams = function(paramString) {
var result = {};
var params = paramString.split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
var paramName = decodeURIComponent(p[0]);
var paramValue = decodeURIComponent(p[1]);
result[paramName] = paramValue;
}
return result;
}
var handleQueryParam = function(paramName, paramValue, oauth) {
var supportedOAuthParams = [ 'code', 'state', 'error', 'error_description' ];
for (var i = 0 ; i< supportedOAuthParams.length ; i++) {
if (paramName === supportedOAuthParams[i]) {
oauth[paramName] = paramValue;
return true;
}
}
return false;
}
parser.parseUri = function() {
var parsedUri = initialParse();
var queryParams = {};
if (parsedUri.queryString) {
queryParams = parseParams(parsedUri.queryString);
}
var oauth = { newUrl: parsedUri.baseUri };
for (var param in queryParams) {
switch (param) {
case 'redirect_fragment':
oauth.fragment = queryParams[param];
break;
default:
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + encodeURIComponent(queryParams[param]);
}
break;
}
}
if (responseMode === 'fragment') {
var fragmentParams = {};
if (parsedUri.fragmentString) {
fragmentParams = parseParams(parsedUri.fragmentString);
}
for (var param in fragmentParams) {
oauth[param] = fragmentParams[param];
}
}
return oauth;
}
}
}
if ( typeof module === "object" && module && typeof module.exports === "object" ) {
@@ -79,6 +79,10 @@
function receiveMessage(event)
{
if (typeof event.data !== 'string') {
return
}
var origin = event.origin;
var data = event.data.split(' ');
if (data.length != 2) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -132,10 +132,8 @@ public class KeycloakAutoConfiguration {
loginConfig.addFirstAuthMethod("KEYCLOAK");
deploymentInfo.setLoginConfig(loginConfig);
deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName());
deploymentInfo.addSecurityConstraints(getSecurityConstraints());
deploymentInfo.addServletExtension(new KeycloakServletExtension());
}
@@ -157,7 +155,6 @@ public class KeycloakAutoConfiguration {
undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
}
undertowSecurityConstraints.add(undertowSecurityConstraint);
}
return undertowSecurityConstraints;
@@ -280,6 +277,11 @@ public class KeycloakAutoConfiguration {
for (String authRole : constraint.getAuthRoles()) {
tomcatConstraint.addAuthRole(authRole);
if(authRole.equals("*") || authRole.equals("**")) {
// For some reasons embed tomcat don't set the auth constraint on true when wildcard is
// used
tomcatConstraint.setAuthConstraint(true);
}
}
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -22,7 +22,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Keycloak Adapters</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+6 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -71,6 +71,11 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
@@ -56,6 +56,8 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
/**
* Abstraction for creating HttpClients. Allows SSL configuration.
@@ -288,6 +290,7 @@ public class HttpClientBuilder {
cm = new SingleClientConnManager(registry);
}
BasicHttpParams params = new BasicHttpParams();
params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
if (proxyHost != null) {
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
@@ -27,35 +27,36 @@ import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
*/
public class IDP implements Serializable {
public static class SingleSignOnService implements Serializable {
private boolean signRequest;
private boolean validateResponseSignature;
private Boolean signRequest;
private Boolean validateResponseSignature;
private String requestBinding;
private String responseBinding;
private String bindingUrl;
private String assertionConsumerServiceUrl;
private boolean validateAssertionSignature;
private Boolean validateAssertionSignature;
private boolean signaturesRequired = false;
public boolean isSignRequest() {
return signRequest;
return signRequest == null ? signaturesRequired : signRequest;
}
public void setSignRequest(boolean signRequest) {
public void setSignRequest(Boolean signRequest) {
this.signRequest = signRequest;
}
public boolean isValidateResponseSignature() {
return validateResponseSignature;
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
}
public void setValidateResponseSignature(boolean validateResponseSignature) {
public void setValidateResponseSignature(Boolean validateResponseSignature) {
this.validateResponseSignature = validateResponseSignature;
}
public boolean isValidateAssertionSignature() {
return validateAssertionSignature;
return validateAssertionSignature == null ? false : validateAssertionSignature;
}
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
public void setValidateAssertionSignature(Boolean validateAssertionSignature) {
this.validateAssertionSignature = validateAssertionSignature;
}
@@ -90,47 +91,52 @@ public class IDP implements Serializable {
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
}
private void setSignaturesRequired(boolean signaturesRequired) {
this.signaturesRequired = signaturesRequired;
}
}
public static class SingleLogoutService implements Serializable {
private boolean signRequest;
private boolean signResponse;
private boolean validateRequestSignature;
private boolean validateResponseSignature;
private Boolean signRequest;
private Boolean signResponse;
private Boolean validateRequestSignature;
private Boolean validateResponseSignature;
private String requestBinding;
private String responseBinding;
private String postBindingUrl;
private String redirectBindingUrl;
private boolean signaturesRequired = false;
public boolean isSignRequest() {
return signRequest;
return signRequest == null ? signaturesRequired : signRequest;
}
public void setSignRequest(boolean signRequest) {
public void setSignRequest(Boolean signRequest) {
this.signRequest = signRequest;
}
public boolean isSignResponse() {
return signResponse;
return signResponse == null ? signaturesRequired : signResponse;
}
public void setSignResponse(boolean signResponse) {
public void setSignResponse(Boolean signResponse) {
this.signResponse = signResponse;
}
public boolean isValidateRequestSignature() {
return validateRequestSignature;
return validateRequestSignature == null ? signaturesRequired : validateRequestSignature;
}
public void setValidateRequestSignature(boolean validateRequestSignature) {
public void setValidateRequestSignature(Boolean validateRequestSignature) {
this.validateRequestSignature = validateRequestSignature;
}
public boolean isValidateResponseSignature() {
return validateResponseSignature;
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
}
public void setValidateResponseSignature(boolean validateResponseSignature) {
public void setValidateResponseSignature(Boolean validateResponseSignature) {
this.validateResponseSignature = validateResponseSignature;
}
@@ -165,6 +171,10 @@ public class IDP implements Serializable {
public void setRedirectBindingUrl(String redirectBindingUrl) {
this.redirectBindingUrl = redirectBindingUrl;
}
private void setSignaturesRequired(boolean signaturesRequired) {
this.signaturesRequired = signaturesRequired;
}
}
public static class HttpClientConfig implements AdapterHttpClientConfig {
@@ -258,6 +268,7 @@ public class IDP implements Serializable {
private SingleLogoutService singleLogoutService;
private List<Key> keys;
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
private boolean signaturesRequired = false;
public String getEntityID() {
return entityID;
@@ -273,6 +284,9 @@ public class IDP implements Serializable {
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
this.singleSignOnService = singleSignOnService;
if (singleSignOnService != null) {
singleSignOnService.setSignaturesRequired(signaturesRequired);
}
}
public SingleLogoutService getSingleLogoutService() {
@@ -281,6 +295,9 @@ public class IDP implements Serializable {
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
this.singleLogoutService = singleLogoutService;
if (singleLogoutService != null) {
singleLogoutService.setSignaturesRequired(signaturesRequired);
}
}
public List<Key> getKeys() {
@@ -315,4 +332,12 @@ public class IDP implements Serializable {
this.httpClientConfig = httpClientConfig;
}
public boolean isSignaturesRequired() {
return signaturesRequired;
}
public void setSignaturesRequired(boolean signaturesRequired) {
this.signaturesRequired = signaturesRequired;
}
}
@@ -114,16 +114,16 @@ public class Key implements Serializable {
return signing;
}
public void setSigning(boolean signing) {
this.signing = signing;
public void setSigning(Boolean signing) {
this.signing = signing != null && signing;
}
public boolean isEncryption() {
return encryption;
}
public void setEncryption(boolean encryption) {
this.encryption = encryption;
public void setEncryption(Boolean encryption) {
this.encryption = encryption != null && encryption;
}
public KeyStoreConfig getKeystore() {
@@ -26,13 +26,14 @@ import java.util.List;
* @version $Revision: 1 $
*/
public class KeycloakSamlAdapter implements Serializable {
private List<SP> sps = new LinkedList<>();
private final List<SP> sps = new LinkedList<>();
public List<SP> getSps() {
return sps;
}
public void setSps(List<SP> sps) {
this.sps = sps;
public void addSp(SP sp) {
sps.add(sp);
}
}
@@ -80,24 +80,24 @@ public class SP implements Serializable {
return forceAuthentication;
}
public void setForceAuthentication(boolean forceAuthentication) {
this.forceAuthentication = forceAuthentication;
public void setForceAuthentication(Boolean forceAuthentication) {
this.forceAuthentication = forceAuthentication != null && forceAuthentication;
}
public boolean isIsPassive() {
return isPassive;
}
public void setIsPassive(boolean isPassive) {
this.isPassive = isPassive;
public void setIsPassive(Boolean isPassive) {
this.isPassive = isPassive != null && isPassive;
}
public boolean isTurnOffChangeSessionIdOnLogin() {
return turnOffChangeSessionIdOnLogin;
}
public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) {
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin != null && turnOffChangeSessionIdOnLogin;
}
public List<Key> getKeys() {
@@ -152,7 +152,7 @@ public class SP implements Serializable {
return autodetectBearerOnly;
}
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
this.autodetectBearerOnly = autodetectBearerOnly;
public void setAutodetectBearerOnly(Boolean autodetectBearerOnly) {
this.autodetectBearerOnly = autodetectBearerOnly != null && autodetectBearerOnly;
}
}
@@ -0,0 +1,59 @@
/*
* 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 org.keycloak.saml.common.parsers.AbstractStaxParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
import java.util.Collections;
import java.util.Set;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.stream.events.StartElement;
/**
*
*/
public abstract class AbstractKeycloakSamlAdapterV1Parser<T> extends AbstractStaxParser<T, KeycloakSamlAdapterV1QNames> {
protected static final QNameEnumLookup<KeycloakSamlAdapterV1QNames> LOOKUP = new QNameEnumLookup(KeycloakSamlAdapterV1QNames.values());
private static final Set<String> ALTERNATE_NAMESPACES = Collections.singleton(XMLConstants.NULL_NS_URI);
public AbstractKeycloakSamlAdapterV1Parser(KeycloakSamlAdapterV1QNames expectedStartElement) {
super(expectedStartElement.getQName(), KeycloakSamlAdapterV1QNames.UNKNOWN_ELEMENT);
}
@Override
protected KeycloakSamlAdapterV1QNames getElementFromName(QName name) {
return (ALTERNATE_NAMESPACES.contains(name.getNamespaceURI()))
? LOOKUP.from(new QName(KeycloakSamlAdapterV1QNames.NS_URI, name.getLocalPart()))
: LOOKUP.from(name);
}
@Override
protected void validateStartElement(StartElement startElement) {
QName name = startElement.getName();
QName validatedQName = ALTERNATE_NAMESPACES.contains(name.getNamespaceURI())
? new QName(name.getNamespaceURI(), expectedStartElement.getLocalPart())
: expectedStartElement;
StaxParserUtil.validate(startElement, validatedQName);
}
}
@@ -1,88 +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.adapters.saml.config.parsers;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ConfigXmlConstants {
public static final String KEYCLOAK_SAML_ADAPTER = "keycloak-saml-adapter";
public static final String SP_ELEMENT = "SP";
public static final String ENTITY_ID_ATTR = "entityID";
public static final String SSL_POLICY_ATTR = "sslPolicy";
public static final String NAME_ID_POLICY_FORMAT_ATTR = "nameIDPolicyFormat";
public static final String FORCE_AUTHENTICATION_ATTR = "forceAuthentication";
public static final String IS_PASSIVE_ATTR = "isPassive";
public static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR = "turnOffChangeSessionIdOnLogin";
public static final String SIGNATURE_ALGORITHM_ATTR = "signatureAlgorithm";
public static final String SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod";
public static final String LOGOUT_PAGE_ATTR = "logoutPage";
public static final String AUTODETECT_BEARER_ONLY_ATTR = "autodetectBearerOnly";
public static final String KEYS_ELEMENT = "Keys";
public static final String KEY_ELEMENT = "Key";
public static final String SIGNING_ATTR = "signing";
public static final String ENCRYPTION_ATTR = "encryption";
public static final String CERTIFICATE_PEM_ELEMENT = "CertificatePem";
public static final String PRIVATE_KEY_PEM_ELEMENT = "PrivateKeyPem";
public static final String PUBLIC_KEY_PEM_ELEMENT = "PublicKeyPem";
public static final String FILE_ATTR = "file";
public static final String TYPE_ATTR = "type";
public static final String RESOURCE_ATTR = "resource";
public static final String PASSWORD_ATTR = "password";
public static final String ALIAS_ATTR = "alias";
public static final String KEYS_STORE_ELEMENT = "KeyStore";
public static final String CERTIFICATE_ELEMENT = "Certificate";
public static final String PRIVATE_KEY_ELEMENT = "PrivateKey";
public static final String PRINCIPAL_NAME_MAPPING_ELEMENT = "PrincipalNameMapping";
public static final String POLICY_ATTR = "policy";
public static final String ATTRIBUTE_ATTR = "attribute";
public static final String ROLE_IDENTIFIERS_ELEMENT = "RoleIdentifiers";
public static final String ATTRIBUTE_ELEMENT = "Attribute";
public static final String NAME_ATTR = "name";
public static final String IDP_ELEMENT = "IDP";
public static final String SIGNATURES_REQUIRED_ATTR = "signaturesRequired";
public static final String SINGLE_SIGN_ON_SERVICE_ELEMENT = "SingleSignOnService";
public static final String SINGLE_LOGOUT_SERVICE_ELEMENT = "SingleLogoutService";
public static final String SIGN_REQUEST_ATTR = "signRequest";
public static final String SIGN_RESPONSE_ATTR = "signResponse";
public static final String REQUEST_BINDING_ATTR = "requestBinding";
public static final String RESPONSE_BINDING_ATTR = "responseBinding";
public static final String BINDING_URL_ATTR = "bindingUrl";
public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
public static final String VALIDATE_ASSERTION_SIGNATURE_ATTR = "validateAssertionSignature";
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 ASSERTION_CONSUMER_SERVICE_URL_ATTR = "assertionConsumerServiceUrl";
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";
}
@@ -59,7 +59,7 @@ public class DeploymentBuilder {
idp.setSingleSignOnService(sso);
idp.setSingleLogoutService(slo);
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter) KeycloakSamlAdapterParser.getInstance().parse(xml);
SP sp = adapter.getSps().get(0);
deployment.setConfigured(true);
deployment.setEntityID(sp.getEntityID());
@@ -0,0 +1,65 @@
/*
* 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 org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class HttpClientParser extends AbstractKeycloakSamlAdapterV1Parser<HttpClientConfig> {
private static final HttpClientParser INSTANCE = new HttpClientParser();
private HttpClientParser() {
super(KeycloakSamlAdapterV1QNames.HTTP_CLIENT);
}
public static HttpClientParser getInstance() {
return INSTANCE;
}
@Override
protected HttpClientConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final HttpClientConfig config = new HttpClientConfig();
final Boolean allowAnyHostname = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALLOW_ANY_HOSTNAME);
config.setAllowAnyHostname(allowAnyHostname == null ? false : allowAnyHostname);
config.setClientKeystore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE));
config.setClientKeystorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE_PASSWORD));
final Integer connPoolSize = StaxParserUtil.getIntegerAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CONNECTION_POOL_SIZE);
config.setConnectionPoolSize(connPoolSize == null ? 0 : connPoolSize);
final Boolean disableTrustManager = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_DISABLE_TRUST_MANAGER);
config.setDisableTrustManager(disableTrustManager == null ? false : disableTrustManager);
config.setProxyUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PROXY_URL));
config.setTruststore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE));
config.setTruststorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE_PASSWORD));
return config;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, HttpClientConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
}
}
@@ -1,163 +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.adapters.saml.config.parsers;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
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>
* @version $Revision: 1 $
*/
public class IDPXmlParser extends AbstractParser {
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
IDP idp = new IDP();
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 = 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)
break;
if (xmlEvent instanceof EndElement) {
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
String endElementName = StaxParserUtil.getEndElementName(endElement);
if (endElementName.equals(ConfigXmlConstants.IDP_ELEMENT))
break;
else
continue;
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired);
idp.setSingleSignOnService(sso);
} else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
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);
idp.setKeys(keys);
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
return idp;
}
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
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(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));
sso.setAssertionConsumerServiceUrl(getAttributeValue(element, ConfigXmlConstants.ASSERTION_CONSUMER_SERVICE_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;
}
}
@@ -0,0 +1,77 @@
/*
* 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 org.keycloak.adapters.saml.config.IDP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class IdpParser extends AbstractKeycloakSamlAdapterV1Parser<IDP> {
private static final IdpParser INSTANCE = new IdpParser();
private IdpParser() {
super(KeycloakSamlAdapterV1QNames.IDP);
}
public static IdpParser getInstance() {
return INSTANCE;
}
@Override
protected IDP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final IDP idp = new IDP();
idp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
Boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURES_REQUIRED);
idp.setSignaturesRequired(signaturesRequired == null ? false : signaturesRequired);
idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_CANONICALIZATION_METHOD));
idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_ALGORITHM));
return idp;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, IDP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case HTTP_CLIENT:
target.setHttpClientConfig(HttpClientParser.getInstance().parse(xmlEventReader));
break;
case KEYS:
target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
break;
case SINGLE_SIGN_ON_SERVICE:
target.setSingleSignOnService(SingleSignOnServiceParser.getInstance().parse(xmlEventReader));
break;
case SINGLE_LOGOUT_SERVICE:
target.setSingleLogoutService(SingleLogoutServiceParser.getInstance().parse(xmlEventReader));
break;
}
}
}
@@ -0,0 +1,79 @@
/*
* 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 org.keycloak.adapters.saml.config.Key;
import org.keycloak.common.util.StringPropertyReplacer;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeyParser extends AbstractKeycloakSamlAdapterV1Parser<Key> {
private static final KeyParser INSTANCE = new KeyParser();
private KeyParser() {
super(KeycloakSamlAdapterV1QNames.KEY);
}
public static KeyParser getInstance() {
return INSTANCE;
}
@Override
protected Key instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
Key key = new Key();
key.setSigning(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNING));
key.setEncryption(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENCRYPTION));
return key;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, Key target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
String value;
switch (element) {
case KEY_STORE:
target.setKeystore(KeyStoreParser.getInstance().parse(xmlEventReader));
break;
case CERTIFICATE_PEM:
StaxParserUtil.advance(xmlEventReader);
value = StaxParserUtil.getElementText(xmlEventReader);
target.setCertificatePem(StringPropertyReplacer.replaceProperties(value));
break;
case PUBLIC_KEY_PEM:
StaxParserUtil.advance(xmlEventReader);
value = StaxParserUtil.getElementText(xmlEventReader);
target.setPublicKeyPem(StringPropertyReplacer.replaceProperties(value));
break;
case PRIVATE_KEY_PEM:
StaxParserUtil.advance(xmlEventReader);
value = StaxParserUtil.getElementText(xmlEventReader);
target.setPrivateKeyPem(StringPropertyReplacer.replaceProperties(value));
break;
}
}
}
@@ -0,0 +1,73 @@
/*
* 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 org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.Key.KeyStoreConfig;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeyStoreParser extends AbstractKeycloakSamlAdapterV1Parser<KeyStoreConfig> {
private static final KeyStoreParser INSTANCE = new KeyStoreParser();
private KeyStoreParser() {
super(KeycloakSamlAdapterV1QNames.KEY_STORE);
}
public static KeyStoreParser getInstance() {
return INSTANCE;
}
@Override
protected KeyStoreConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final KeyStoreConfig keyStore = new Key.KeyStoreConfig();
keyStore.setType(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TYPE));
keyStore.setAlias(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
keyStore.setFile(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FILE));
keyStore.setResource(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESOURCE));
keyStore.setPassword(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
if (keyStore.getFile() == null && keyStore.getResource() == null) {
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
}
return keyStore;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, KeyStoreConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case CERTIFICATE:
target.setCertificateAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
break;
case PRIVATE_KEY:
target.setPrivateKeyAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
target.setPrivateKeyPassword(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
break;
}
}
}
@@ -1,145 +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.adapters.saml.config.parsers;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeyXmlParser extends AbstractParser {
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEY_ELEMENT);
Key key = new Key();
key.setSigning(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
key.setEncryption(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.ENCRYPTION_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.KEY_ELEMENT))
break;
else
throw logger.parserUnknownEndElement(endElementName);
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT)) {
key.setKeystore(parseKeyStore(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
key.setCertificatePem(SPXmlParser.getElementText(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
key.setPublicKeyPem(SPXmlParser.getElementText(xmlEventReader));
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
key.setPrivateKeyPem(SPXmlParser.getElementText(xmlEventReader));
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
return key;
}
protected Key.KeyStoreConfig parseKeyStore(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_STORE_ELEMENT);
Key.KeyStoreConfig keyStore = new Key.KeyStoreConfig();
keyStore.setType(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
keyStore.setAlias(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
keyStore.setFile(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
keyStore.setResource(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
if (keyStore.getFile() == null && keyStore.getResource() == null) {
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
}
keyStore.setPassword(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
if (keyStore.getPassword() == null) {
throw new ParsingException("KeyStore element must have the password attribute set");
}
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.KEYS_STORE_ELEMENT))
break;
else
continue;
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
keyStore.setCertificateAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
if (keyStore.getCertificateAlias() == null) {
throw new ParsingException("KeyStore Certificate element must have the alias attribute set");
}
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
keyStore.setPrivateKeyAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
if (keyStore.getPrivateKeyAlias() == null) {
throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
}
keyStore.setPrivateKeyPassword(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
if (keyStore.getPrivateKeyPassword() == null) {
throw new ParsingException("KeyStore PrivateKey element must have the password attribute set");
}
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
return keyStore;
}
@Override
public boolean supports(QName qname) {
return false;
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2018 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 org.keycloak.saml.common.ErrorCodes;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.parsers.StaxParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
/**
*
* @author hmlnarik
*/
public class KeycloakSamlAdapterParser extends AbstractParser {
private interface ParserFactory {
public StaxParser create();
}
private static final Map<QName, ParserFactory> PARSERS = new HashMap<QName, ParserFactory>();
// No-namespace variant
private static final QName ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1 = new QName(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName().getLocalPart());
static {
PARSERS.put(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName(), new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
PARSERS.put(ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1, new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
}
private static final KeycloakSamlAdapterParser INSTANCE = new KeycloakSamlAdapterParser();
public static KeycloakSamlAdapterParser getInstance() {
return INSTANCE;
}
protected KeycloakSamlAdapterParser() {
}
/**
* @see {@link org.keycloak.saml.common.parsers.ParserNamespaceSupport#parse(XMLEventReader)}
*/
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
while (xmlEventReader.hasNext()) {
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
if (xmlEvent instanceof StartElement) {
StartElement startElement = (StartElement) xmlEvent;
final QName name = startElement.getName();
ParserFactory pf = PARSERS.get(name);
if (pf == null) {
throw logger.parserException(new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + name + "::location="
+ startElement.getLocation()));
}
return pf.create().parse(xmlEventReader);
}
StaxParserUtil.getNextEvent(xmlEventReader);
}
throw new RuntimeException(ErrorCodes.FAILED_PARSING + "SAML Parsing has failed");
}
}
@@ -18,12 +18,9 @@
package org.keycloak.adapters.saml.config.parsers;
import org.keycloak.adapters.saml.config.KeycloakSamlAdapter;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
@@ -31,32 +28,33 @@ import javax.xml.stream.events.StartElement;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakSamlAdapterXMLParser extends AbstractParser {
public class KeycloakSamlAdapterV1Parser extends AbstractKeycloakSamlAdapterV1Parser<KeycloakSamlAdapter> {
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
KeycloakSamlAdapter adapter = new KeycloakSamlAdapter();
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYCLOAK_SAML_ADAPTER);
while (xmlEventReader.hasNext()) {
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.SP_ELEMENT)) {
SPXmlParser parser = new SPXmlParser();
SP sp = (SP)parser.parse(xmlEventReader);
if (sp != null) adapter.getSps().add(sp);
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
private static final KeycloakSamlAdapterV1Parser INSTANCE = new KeycloakSamlAdapterV1Parser();
}
return adapter;
private KeycloakSamlAdapterV1Parser() {
super(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER);
}
public static KeycloakSamlAdapterV1Parser getInstance() {
return INSTANCE;
}
@Override
public boolean supports(QName qname) {
return false;
protected KeycloakSamlAdapter instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
return new KeycloakSamlAdapter();
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, KeycloakSamlAdapter target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case SP:
target.addSp(SpParser.getInstance().parse(xmlEventReader));
break;
default:
// Ignore unknown tags
StaxParserUtil.bypassElementBlock(xmlEventReader);
}
}
}
@@ -0,0 +1,114 @@
/*
* Copyright 2018 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 org.keycloak.saml.processing.core.parsers.util.HasQName;
import javax.xml.namespace.QName;
/**
*
* @author hmlnarik
*/
public enum KeycloakSamlAdapterV1QNames implements HasQName {
ATTRIBUTE("Attribute"),
CERTIFICATE("Certificate"),
CERTIFICATE_PEM("CertificatePem"),
HTTP_CLIENT("HttpClient"),
IDP("IDP"),
KEY("Key"),
KEYCLOAK_SAML_ADAPTER("keycloak-saml-adapter"),
KEYS("Keys"),
KEY_STORE("KeyStore"),
PRINCIPAL_NAME_MAPPING("PrincipalNameMapping"),
PRIVATE_KEY("PrivateKey"),
PRIVATE_KEY_PEM("PrivateKeyPem"),
PUBLIC_KEY_PEM("PublicKeyPem"),
ROLE_IDENTIFIERS("RoleIdentifiers"),
SINGLE_LOGOUT_SERVICE("SingleLogoutService"),
SINGLE_SIGN_ON_SERVICE("SingleSignOnService"),
SP("SP"),
ATTR_ALIAS(null, "alias"),
ATTR_ALLOW_ANY_HOSTNAME(null, "allowAnyHostname"),
ATTR_ASSERTION_CONSUMER_SERVICE_URL(null, "assertionConsumerServiceUrl"),
ATTR_ATTRIBUTE(null, "attribute"),
ATTR_AUTODETECT_BEARER_ONLY(null, "autodetectBearerOnly"),
ATTR_BINDING_URL(null, "bindingUrl"),
ATTR_CLIENT_KEYSTORE(null, "clientKeystore"),
ATTR_CLIENT_KEYSTORE_PASSWORD(null, "clientKeystorePassword"),
ATTR_CONNECTION_POOL_SIZE(null, "connectionPoolSize"),
ATTR_DISABLE_TRUST_MANAGER(null, "disableTrustManager"),
ATTR_ENCRYPTION(null, "encryption"),
ATTR_ENTITY_ID(null, "entityID"),
ATTR_FILE(null, "file"),
ATTR_FORCE_AUTHENTICATION(null, "forceAuthentication"),
ATTR_IS_PASSIVE(null, "isPassive"),
ATTR_LOGOUT_PAGE(null, "logoutPage"),
ATTR_NAME(null, "name"),
ATTR_NAME_ID_POLICY_FORMAT(null, "nameIDPolicyFormat"),
ATTR_PASSWORD(null, "password"),
ATTR_POLICY(null, "policy"),
ATTR_POST_BINDING_URL(null, "postBindingUrl"),
ATTR_PROXY_URL(null, "proxyUrl"),
ATTR_REDIRECT_BINDING_URL(null, "redirectBindingUrl"),
ATTR_REQUEST_BINDING(null, "requestBinding"),
ATTR_RESOURCE(null, "resource"),
ATTR_RESPONSE_BINDING(null, "responseBinding"),
ATTR_SIGNATURES_REQUIRED(null, "signaturesRequired"),
ATTR_SIGNATURE_ALGORITHM(null, "signatureAlgorithm"),
ATTR_SIGNATURE_CANONICALIZATION_METHOD(null, "signatureCanonicalizationMethod"),
ATTR_SIGNING(null, "signing"),
ATTR_SIGN_REQUEST(null, "signRequest"),
ATTR_SIGN_RESPONSE(null, "signResponse"),
ATTR_SSL_POLICY(null, "sslPolicy"),
ATTR_TRUSTSTORE(null, "truststore"),
ATTR_TRUSTSTORE_PASSWORD(null, "truststorePassword"),
ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN(null, "turnOffChangeSessionIdOnLogin"),
ATTR_TYPE(null, "type"),
ATTR_VALIDATE_ASSERTION_SIGNATURE(null, "validateAssertionSignature"),
ATTR_VALIDATE_REQUEST_SIGNATURE(null, "validateRequestSignature"),
ATTR_VALIDATE_RESPONSE_SIGNATURE(null, "validateResponseSignature"),
UNKNOWN_ELEMENT("")
;
public static final String NS_URI = "urn:keycloak:saml:adapter";
private final QName qName;
private KeycloakSamlAdapterV1QNames(String localName) {
this(NS_URI, localName);
}
private KeycloakSamlAdapterV1QNames(HasQName source) {
this.qName = source.getQName();
}
private KeycloakSamlAdapterV1QNames(String nsUri, String localName) {
this.qName = new QName(nsUri == null ? null : nsUri, localName);
}
@Override
public QName getQName() {
return qName;
}
public QName getQName(String prefix) {
return new QName(this.qName.getNamespaceURI(), this.qName.getLocalPart(), prefix);
}
}
@@ -0,0 +1,59 @@
/*
* 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 org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import java.util.LinkedList;
import java.util.List;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeysParser extends AbstractKeycloakSamlAdapterV1Parser<List<Key>> {
private static final KeysParser INSTANCE = new KeysParser();
private KeysParser() {
super(KeycloakSamlAdapterV1QNames.KEYS);
}
public static KeysParser getInstance() {
return INSTANCE;
}
@Override
protected List<Key> instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
return new LinkedList<>();
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, List<Key> target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case KEY:
target.add(KeyParser.getInstance().parse(xmlEventReader));
break;
}
}
}
@@ -1,76 +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.adapters.saml.config.parsers;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeysXmlParser extends AbstractParser {
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_ELEMENT);
List<Key> keys = new LinkedList<>();
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.KEYS_ELEMENT))
break;
else
throw logger.parserUnknownEndElement(endElementName);
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.KEY_ELEMENT)) {
KeyXmlParser parser = new KeyXmlParser();
Key key = (Key)parser.parse(xmlEventReader);
keys.add(key);
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
return keys;
}
@Override
public boolean supports(QName qname) {
return false;
}
}
@@ -0,0 +1,56 @@
/*
* 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 org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class PrincipalNameMappingParser extends AbstractKeycloakSamlAdapterV1Parser<SP.PrincipalNameMapping> {
private static final PrincipalNameMappingParser INSTANCE = new PrincipalNameMappingParser();
private PrincipalNameMappingParser() {
super(KeycloakSamlAdapterV1QNames.PRINCIPAL_NAME_MAPPING);
}
public static PrincipalNameMappingParser getInstance() {
return INSTANCE;
}
@Override
protected SP.PrincipalNameMapping instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
mapping.setPolicy(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POLICY));
mapping.setAttributeName(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ATTRIBUTE));
return mapping;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, SP.PrincipalNameMapping target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
}
}
@@ -0,0 +1,57 @@
/*
* 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 org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import java.util.HashSet;
import java.util.Set;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RoleMappingParser extends AbstractKeycloakSamlAdapterV1Parser<Set<String>> {
private static final RoleMappingParser INSTANCE = new RoleMappingParser();
private RoleMappingParser() {
super(KeycloakSamlAdapterV1QNames.ROLE_IDENTIFIERS);
}
public static RoleMappingParser getInstance() {
return INSTANCE;
}
@Override
protected Set<String> instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
return new HashSet<>();
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, Set<String> target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case ATTRIBUTE:
target.add(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_NAME));
break;
}
}
}
@@ -1,181 +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.adapters.saml.config.parsers;
import org.keycloak.adapters.saml.config.IDP;
import org.keycloak.adapters.saml.config.Key;
import org.keycloak.adapters.saml.config.SP;
import org.keycloak.common.util.StringPropertyReplacer;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.parsers.AbstractParser;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SPXmlParser extends AbstractParser {
public static String getAttributeValue(StartElement startElement, String tag) {
String str = StaxParserUtil.getAttributeValue(startElement, tag);
if (str != null)
return StringPropertyReplacer.replaceProperties(str);
else
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)
return defaultValue;
return Boolean.valueOf(result);
}
public static boolean getBooleanAttributeValue(StartElement startElement, String tag) {
return getBooleanAttributeValue(startElement, tag, false);
}
public static String getElementText(XMLEventReader xmlEventReader) throws ParsingException {
String result = StaxParserUtil.getElementText(xmlEventReader);
if (result != null)
result = StringPropertyReplacer.replaceProperties(result);
return result;
}
@Override
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.SP_ELEMENT);
SP sp = new SP();
String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
if (entityID == null) {
throw new ParsingException("entityID must be set on SP");
}
sp.setEntityID(entityID);
sp.setSslPolicy(getAttributeValue(startElement, ConfigXmlConstants.SSL_POLICY_ATTR));
sp.setLogoutPage(getAttributeValue(startElement, ConfigXmlConstants.LOGOUT_PAGE_ATTR));
sp.setNameIDPolicyFormat(getAttributeValue(startElement, ConfigXmlConstants.NAME_ID_POLICY_FORMAT_ATTR));
sp.setForceAuthentication(getBooleanAttributeValue(startElement, ConfigXmlConstants.FORCE_AUTHENTICATION_ATTR));
sp.setIsPassive(getBooleanAttributeValue(startElement, ConfigXmlConstants.IS_PASSIVE_ATTR));
sp.setAutodetectBearerOnly(getBooleanAttributeValue(startElement, ConfigXmlConstants.AUTODETECT_BEARER_ONLY_ATTR));
sp.setTurnOffChangeSessionIdOnLogin(getBooleanAttributeValue(startElement, ConfigXmlConstants.TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_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.SP_ELEMENT))
break;
else
continue;
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
KeysXmlParser parser = new KeysXmlParser();
List<Key> keys = (List<Key>) parser.parse(xmlEventReader);
sp.setKeys(keys);
} else if (tag.equals(ConfigXmlConstants.PRINCIPAL_NAME_MAPPING_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
String policy = getAttributeValue(element, ConfigXmlConstants.POLICY_ATTR);
if (policy == null) {
throw new ParsingException("PrincipalNameMapping element must have the policy attribute set");
}
String attribute = getAttributeValue(element, ConfigXmlConstants.ATTRIBUTE_ATTR);
SP.PrincipalNameMapping mapping = new SP.PrincipalNameMapping();
mapping.setPolicy(policy);
mapping.setAttributeName(attribute);
sp.setPrincipalNameMapping(mapping);
} else if (tag.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT)) {
parseRoleMapping(xmlEventReader, sp);
} else if (tag.equals(ConfigXmlConstants.IDP_ELEMENT)) {
IDPXmlParser parser = new IDPXmlParser();
IDP idp = (IDP) parser.parse(xmlEventReader);
sp.setIdp(idp);
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
return sp;
}
protected void parseRoleMapping(XMLEventReader xmlEventReader, SP sp) throws ParsingException {
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
StaxParserUtil.validate(startElement, ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT);
Set<String> roleAttributes = new HashSet<>();
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;
}
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
if (startElement == null)
break;
String tag = StaxParserUtil.getStartElementName(startElement);
if (tag.equals(ConfigXmlConstants.ATTRIBUTE_ELEMENT)) {
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
String attributeValue = getAttributeValue(element, ConfigXmlConstants.NAME_ATTR);
if (attributeValue == null) {
throw new ParsingException("RoleMapping Attribute element must have the name attribute set");
}
roleAttributes.add(attributeValue);
} else {
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
}
}
sp.setRoleAttributes(roleAttributes);
}
@Override
public boolean supports(QName qname) {
return false;
}
}
@@ -0,0 +1,62 @@
/*
* 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 org.keycloak.adapters.saml.config.IDP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SingleLogoutServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleLogoutService> {
private static final SingleLogoutServiceParser INSTANCE = new SingleLogoutServiceParser();
private SingleLogoutServiceParser() {
super(KeycloakSamlAdapterV1QNames.SINGLE_LOGOUT_SERVICE);
}
public static SingleLogoutServiceParser getInstance() {
return INSTANCE;
}
@Override
protected IDP.SingleLogoutService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
slo.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
slo.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
slo.setValidateRequestSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_REQUEST_SIGNATURE));
slo.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
slo.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
slo.setSignResponse(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_RESPONSE));
slo.setPostBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_POST_BINDING_URL));
slo.setRedirectBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REDIRECT_BINDING_URL));
return slo;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleLogoutService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
}
}
@@ -0,0 +1,61 @@
/*
* 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 org.keycloak.adapters.saml.config.IDP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SingleSignOnServiceParser extends AbstractKeycloakSamlAdapterV1Parser<IDP.SingleSignOnService> {
private static final SingleSignOnServiceParser INSTANCE = new SingleSignOnServiceParser();
private SingleSignOnServiceParser() {
super(KeycloakSamlAdapterV1QNames.SINGLE_SIGN_ON_SERVICE);
}
public static SingleSignOnServiceParser getInstance() {
return INSTANCE;
}
@Override
protected IDP.SingleSignOnService instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
sso.setSignRequest(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGN_REQUEST));
sso.setValidateResponseSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_RESPONSE_SIGNATURE));
sso.setValidateAssertionSignature(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_VALIDATE_ASSERTION_SIGNATURE));
sso.setRequestBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_REQUEST_BINDING));
sso.setResponseBinding(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESPONSE_BINDING));
sso.setBindingUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_BINDING_URL));
sso.setAssertionConsumerServiceUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ASSERTION_CONSUMER_SERVICE_URL));
return sso;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, IDP.SingleSignOnService target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
}
}
@@ -0,0 +1,80 @@
/*
* 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 org.keycloak.adapters.saml.config.SP;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.StartElement;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SpParser extends AbstractKeycloakSamlAdapterV1Parser<SP> {
private static final SpParser INSTANCE = new SpParser();
private SpParser() {
super(KeycloakSamlAdapterV1QNames.SP);
}
public static SpParser getInstance() {
return INSTANCE;
}
@Override
protected SP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
final SP sp = new SP();
sp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
sp.setSslPolicy(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SSL_POLICY));
sp.setLogoutPage(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_LOGOUT_PAGE));
sp.setNameIDPolicyFormat(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_NAME_ID_POLICY_FORMAT));
sp.setForceAuthentication(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FORCE_AUTHENTICATION));
sp.setIsPassive(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_IS_PASSIVE));
sp.setAutodetectBearerOnly(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_AUTODETECT_BEARER_ONLY));
sp.setTurnOffChangeSessionIdOnLogin(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN));
return sp;
}
@Override
protected void processSubElement(XMLEventReader xmlEventReader, SP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
switch (element) {
case KEYS:
target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
break;
case PRINCIPAL_NAME_MAPPING:
target.setPrincipalNameMapping(PrincipalNameMappingParser.getInstance().parse(xmlEventReader));
break;
case ROLE_IDENTIFIERS:
target.setRoleAttributes(RoleMappingParser.getInstance().parse(xmlEventReader));
break;
case IDP:
target.setIdp(IdpParser.getInstance().parse(xmlEventReader));
break;
}
}
}
@@ -35,6 +35,7 @@ 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.common.util.DocumentUtil;
import org.keycloak.saml.processing.core.parsers.saml.xmldsig.XmlDSigQNames;
import org.keycloak.saml.processing.core.util.NamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -88,7 +89,7 @@ public class SamlDescriptorIDPKeysExtractor {
}
private KeyInfo processKeyDescriptor(Element keyDescriptor) throws MarshalException {
NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), JBossSAMLConstants.KEY_INFO.get());
NodeList childNodes = keyDescriptor.getElementsByTagNameNS(JBossSAMLURIConstants.XMLDSIG_NSURI.get(), XmlDSigQNames.KEY_INFO.getQName().getLocalPart());
if (childNodes.getLength() == 0) {
return null;
@@ -14,7 +14,7 @@ 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.adapters.saml.config.parsers.KeycloakSamlAdapterV1QNames;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.saml.common.exceptions.ParsingException;
@@ -41,15 +41,15 @@ public class HttpAdapterUtilsTest {
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));
assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()), notNullValue());
assertThat(res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).size(), equalTo(2));
KeyInfo ki;
KeyName keyName;
X509Data x509data;
X509Certificate x509certificate;
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(0);
ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).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)));
@@ -63,7 +63,7 @@ public class HttpAdapterUtilsTest {
assertThat(x509certificate, notNullValue());
assertThat(x509certificate.getSigAlgName(), equalTo("SHA256withRSA"));
ki = res.get(ConfigXmlConstants.SIGNING_ATTR).get(1);
ki = res.get(KeycloakSamlAdapterV1QNames.ATTR_SIGNING.getQName().getLocalPart()).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)));
@@ -30,6 +30,8 @@ import java.io.InputStream;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.keycloak.saml.common.exceptions.ParsingException;
import java.io.IOException;
import org.hamcrest.Matchers;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -67,7 +69,7 @@ public class KeycloakSamlAdapterXMLParserTest {
@Test
public void testValidationKeyInvalid() throws Exception {
InputStream schemaIs = KeycloakSamlAdapterXMLParser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream schemaIs = KeycloakSamlAdapterV1Parser.class.getResourceAsStream(CURRENT_XSD_LOCATION);
InputStream is = getClass().getResourceAsStream("keycloak-saml-invalid.xml");
assertNotNull(is);
assertNotNull(schemaIs);
@@ -77,12 +79,14 @@ public class KeycloakSamlAdapterXMLParserTest {
}
@Test
public void testXmlParser() throws Exception {
InputStream is = getClass().getResourceAsStream("keycloak-saml.xml");
assertNotNull(is);
KeycloakSamlAdapterXMLParser parser = new KeycloakSamlAdapterXMLParser();
public void testParseSimpleFileNoNamespace() throws Exception {
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-no-namespace.xml", KeycloakSamlAdapter.class);
}
@Test
public void testXmlParserBaseFile() throws Exception {
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml.xml", KeycloakSamlAdapter.class);
KeycloakSamlAdapter config = (KeycloakSamlAdapter)parser.parse(is);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
@@ -121,7 +125,7 @@ public class KeycloakSamlAdapterXMLParserTest {
assertEquals("POST", idp.getSingleSignOnService().getRequestBinding());
assertEquals("url", idp.getSingleSignOnService().getBindingUrl());
assertTrue(idp.getSingleLogoutService().isSignRequest());
assertFalse(idp.getSingleLogoutService().isSignRequest());
assertTrue(idp.getSingleLogoutService().isSignResponse());
assertTrue(idp.getSingleLogoutService().isValidateRequestSignature());
assertTrue(idp.getSingleLogoutService().isValidateResponseSignature());
@@ -135,14 +139,17 @@ public class KeycloakSamlAdapterXMLParserTest {
assertEquals("cert pem", idp.getKeys().get(0).getCertificatePem());
}
private <T> T parseKeycloakSamlAdapterConfig(String fileName, Class<T> targetClass) throws ParsingException, IOException {
try (InputStream is = getClass().getResourceAsStream(fileName)) {
KeycloakSamlAdapterParser parser = KeycloakSamlAdapterParser.getInstance();
return targetClass.cast(parser.parse(is));
}
}
@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);
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-multiple-signing-keys.xml", KeycloakSamlAdapter.class);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
@@ -158,11 +165,7 @@ public class KeycloakSamlAdapterXMLParserTest {
@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);
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-wth-http-client-settings.xml", KeycloakSamlAdapter.class);
assertNotNull(config);
assertEquals(1, config.getSps().size());
SP sp = config.getSps().get(0);
@@ -178,4 +181,66 @@ public class KeycloakSamlAdapterXMLParserTest {
assertThat(idp.getHttpClientConfig().isAllowAnyHostname(), is(true));
assertThat(idp.getHttpClientConfig().isDisableTrustManager(), is(true));
}
@Test
public void testXmlParserSystemPropertiesNoPropertiesSet() throws Exception {
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
assertNotNull(config);
assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertThat(sp.getEntityID(), is("sp"));
assertThat(sp.getSslPolicy(), is("${keycloak-saml-properties.sslPolicy}"));
assertThat(idp.isSignaturesRequired(), is(false));
assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
// These should take default from IDP.signaturesRequired
assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(false));
assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(false));
assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
}
@Test
public void testXmlParserSystemPropertiesWithPropertiesSet() throws Exception {
try {
System.setProperty("keycloak-saml-properties.entityID", "meid");
System.setProperty("keycloak-saml-properties.sslPolicy", "INTERNAL");
System.setProperty("keycloak-saml-properties.signaturesRequired", "true");
KeycloakSamlAdapter config = parseKeycloakSamlAdapterConfig("keycloak-saml-properties.xml", KeycloakSamlAdapter.class);
assertNotNull(config);
assertThat(config.getSps(), Matchers.contains(instanceOf(SP.class)));
SP sp = config.getSps().get(0);
IDP idp = sp.getIdp();
assertThat(sp.getEntityID(), is("meid"));
assertThat(sp.getSslPolicy(), is("INTERNAL"));
assertThat(idp.isSignaturesRequired(), is(true));
assertThat(idp.getSingleLogoutService().isSignRequest(), is(true));
assertThat(idp.getSingleLogoutService().isSignResponse(), is(false));
assertThat(idp.getSingleSignOnService().isSignRequest(), is(true));
assertThat(idp.getSingleSignOnService().isValidateResponseSignature(), is(true));
// These should take default from IDP.signaturesRequired
assertThat(idp.getSingleLogoutService().isValidateRequestSignature(), is(true));
assertThat(idp.getSingleLogoutService().isValidateResponseSignature(), is(true));
// This is false by default
assertThat(idp.getSingleSignOnService().isValidateAssertionSignature(), is(false));
} finally {
System.clearProperty("keycloak-saml-properties.entityID");
System.clearProperty("keycloak-saml-properties.sslPolicy");
System.clearProperty("keycloak-saml-properties.signaturesRequired");
}
}
}
@@ -15,30 +15,41 @@
~ 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="http://localhost:8081/sales-post-sig-email/"
<keycloak-saml-adapter>
<SP entityID="${keycloak-saml-properties.entityID:sp}"
sslPolicy="EXTERNAL"
logoutPage="/logout.jsp"
forceAuthentication="false">
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="true">
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
<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_NAME_ID"/>
<PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="attribute"/>
<RoleIdentifiers>
<Attribute name="Role"/>
<Attribute name="member"/>
</RoleIdentifiers>
<IDP entityID="idp">
<IDP entityID="idp"
signatureAlgorithm="RSA_SHA256"
signatureCanonicalizationMethod="canon"
signaturesRequired="true"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
bindingUrl="url"
/>
<SingleLogoutService
@@ -46,18 +57,18 @@
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="POST"
requestBinding="REDIRECT"
responseBinding="POST"
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
<CertificatePem>
cert pem
</CertificatePem>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
</SP>
</keycloak-saml-adapter>
@@ -0,0 +1,74 @@
<!--
~ 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_9.xsd">
<SP entityID="${keycloak-saml-properties.entityID:sp}"
sslPolicy="${keycloak-saml-properties.sslPolicy}"
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_SHA256"
signatureCanonicalizationMethod="canon"
signaturesRequired="${keycloak-saml-properties.signaturesRequired:false}"
>
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="url"
/>
<SingleLogoutService
signRequest="true"
signResponse="false"
requestBinding="REDIRECT"
responseBinding="POST"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl"
/>
<Keys>
<Key signing="true">
<CertificatePem>
cert pem
</CertificatePem>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
@@ -57,7 +57,7 @@
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signRequest="false"
signResponse="true"
requestBinding="REDIRECT"
responseBinding="POST"
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</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>3.4.1.Final-SNAPSHOT</version>
<version>4.0.0.Beta1</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
Loaded 100 of 4096 files, more files were not shown because too many files have changed in this diff. Show more