Compare commits

...
Author SHA1 Message Date
keycloak-bot 1fc98ad9e3 Set version to 3.2.0.Final 2017-07-05 05:31:21 +00:00
keycloak-bot 51769f2e78 Set version to 3.2.0.Final-SNAPSHOT 2017-06-30 09:28:29 +00:00
keycloak-bot b418dcafc3 Set version to 3.2.0.CR1 2017-06-30 08:01:33 +00:00
Stian Thorgersen 124ae402e2 KEYCLOAK-5091
Revert to WildFly 10 for 3.2 release

KEYCLOAK-4189 Fix cluster tests failures
2017-06-30 09:34:12 +02:00
Stian Thorgersen fdb80d4319 Fix console tests (#4277) 2017-06-30 08:49:18 +02:00
Stian Thorgersen f0f1b85582 KEYCLOAK-5116 (#4276)
Authz tab not showing
2017-06-30 08:48:28 +02:00
Stan Silvert 6874cdc3b2 KEYCLOAK-4997 KEYCLOAK-4866 KEYCLOAK-4895 Upgrade to latest AngularJS, (#4275)
jquery, and others.
2017-06-30 05:55:47 +02:00
Bill Burke 19bdf09e3d Merge pull request #4274 from patriot1burke/master
bad logic will result in NPE
2017-06-29 21:36:12 -04:00
Bill Burke 999dff353c Merge remote-tracking branch 'upstream/master' 2017-06-29 17:37:45 -04:00
Bill Burke f5389b0e17 don't clean up properly 2017-06-29 17:36:45 -04:00
hmlnarik b4ad69b841 KEYCLOAK-5115 (#4272) 2017-06-29 15:50:50 +02:00
vramik 6ba3687b76 KEYCLOAK-5114 Fix UsersTest on auth-server-wildfly (#4271) 2017-06-29 14:39:59 +02:00
Sebastien Blanc 500a21685f KEYCLOAK-5082 : Add new redirect-rewrite-rule parameters for the adapters (#4255)
* add rewrite rule config property

* add subsystem support for redirect rewrite

* update deployment unit test

* add license headers

* Optimize rewrite method
2017-06-29 12:50:42 +02:00
Stian Thorgersen 620bea3553 Merge pull request #4270 from stianst/KEYCLOAK-5107
KEYCLOAK-5107 Fix FineGrainAdminUnitTest and IllegalAdminUpgradeTest …
2017-06-29 08:54:59 +02:00
Stian Thorgersen 5e225c2bd5 Merge pull request #4266 from CoreFiling/FullNameMapper
Fallback to using username in FullNameMapper
2017-06-29 07:28:42 +02:00
Stian Thorgersen c9bc321d2a Merge pull request #4269 from stianst/dockerdockerdocker
KEYCLOAK-3592 Docker auth implementation
2017-06-29 07:23:47 +02:00
Stian Thorgersen 74fe9249d5 Merge pull request #4216 from machielg/master
KEYCLOAK-5026 Store credentials
2017-06-29 06:52:16 +02:00
Stian Thorgersen 9f814c6cf1 KEYCLOAK-5107 Fix FineGrainAdminUnitTest and IllegalAdminUpgradeTest on auth-server-wildfly 2017-06-29 06:46:21 +02:00
Josh Cain 89fcddd605 KEYCLOAK-3592 Docker auth implementation 2017-06-29 06:37:34 +02:00
Stian Thorgersen 0b108d83af Merge pull request #4268 from hmlnarik/KEYCLOAK-5106-BasicSamlTest-testNoPortInDestination-fails-on-auth-server-wildfly
KEYCLOAK-5106 Fix BasicSamlTest on auth-server-wildfly
2017-06-29 05:13:21 +02:00
Hynek Mlnarik 5e16a32f86 KEYCLOAK-5106 Fix BasicSamlTest on auth-server-wildfly 2017-06-28 20:47:43 +02:00
Pavel Drozd 6b846b53e4 Merge pull request #4263 from mhajas/KEYCLOAK-5097
KEYCLOAK-5097 fix property name
2017-06-28 13:23:36 +02:00
Stian Thorgersen e964b156cc Merge pull request #4264 from stianst/KEYCLOAK-5074
KEYCLOAK-5074 Allow updating client secret through client registratio…
2017-06-28 11:40:04 +02:00
Jay Anslow bdc9e8d2c3 Omit empty name claim in FullNameMapper
If a user has no first or last name, don't add the `name` claim.
2017-06-28 09:40:57 +01:00
Stian Thorgersen ce4506f367 Merge pull request #4261 from hmlnarik/KEYCLOAK-4377-null
KEYCLOAK-4377
2017-06-28 08:21:20 +02:00
Stian Thorgersen 55d0ad3a50 Merge pull request #4234 from samuelMangot/master
Email - I18n - added missing german text
2017-06-28 08:20:50 +02:00
Stian Thorgersen d90235d1bd Merge pull request #4245 from hokuda/email-messages-japanese
fix email messages in Japanese
2017-06-28 08:20:21 +02:00
Stian Thorgersen 1220d7f898 KEYCLOAK-5074 Allow updating client secret through client registration service 2017-06-28 08:11:51 +02:00
Samuel Mangot f5545eabdc Email - I18n - fixed another grammar error 2017-06-27 20:30:30 +02:00
Samuel Mangot 3db8f97248 Email - I18n - removed remaining " and fixe grammar error 2017-06-27 18:04:41 +02:00
Samuel Mangot 48421cbc43 Email - I18n - removed "" around text placeholder 2017-06-27 16:55:10 +02:00
Stian Thorgersen 7010c39544 Merge pull request #4265 from stianst/master
Fix dependency exclusions in server-dist to make sure dependency vers…
2017-06-27 15:56:21 +02:00
Hynek Mlnarik a3ccac2012 KEYCLOAK-4377 2017-06-27 14:34:47 +02:00
Stian Thorgersen 6bbdc13544 Upgrade EAP 2017-06-27 14:26:05 +02:00
Stian Thorgersen 073f1eda54 Fix dependency exclusions in server-dist to make sure dependency versions are inherited from WF 2017-06-27 14:24:22 +02:00
mhajas 29c2ef4c60 KEYCLOAK-5097 fix property name 2017-06-27 12:28:32 +02:00
Pavel Drozd 947254e14f Merge pull request #4222 from vmuzikar/KEYCLOAK-5055
KEYCLOAK-4787, KEYCLOAK-5055 Stabilize UI tests
2017-06-27 11:42:21 +02:00
Pavel Drozd b02d48f772 Merge pull request #4249 from vramik/KEYCLOAK-5048
KEYCLOAK-5048 missing keycloak version in logs when staring auth-serv…
2017-06-27 11:40:26 +02:00
Stian Thorgersen 4be0e36306 Merge pull request #4208 from ASzc/KEYCLOAK-4758
KEYCLOAK-4758
2017-06-27 11:35:43 +02:00
Stian Thorgersen b041146a3f Merge pull request #4200 from guigarage/servlet-config
KeycloakConfigResolver config for servlet filter
2017-06-27 10:45:29 +02:00
Stian Thorgersen 56c5996aff Merge pull request #4259 from stianst/abstractj-KEYCLOAK-4444
KEYCLOAK-4444
2017-06-27 10:44:30 +02:00
Stian Thorgersen fa165806f9 Merge pull request #4258 from stianst/KEYCLOAK-4984
KEYCLOAK-4984 Don't update client registration access token on read
2017-06-27 10:44:06 +02:00
Machiel Groeneveld 7849191ec7 Merge branch 'master' into master 2017-06-27 10:27:07 +02:00
Stian Thorgersen 06a318d7d5 KEYCLOAK-4444 Update for fine grained permissions 2017-06-27 08:38:51 +02:00
Bruno Oliveira 361ab1c988 [KEYCLOAK-4444] Allow sending test email 2017-06-27 08:38:36 +02:00
Stian Thorgersen c1c1a81a4e Merge pull request #4138 from ASzc/KEYCLOAK-4752
KEYCLOAK-4752
2017-06-27 08:34:00 +02:00
Stian Thorgersen b4d39ca061 KEYCLOAK-4984 Don't update client registration access token on read 2017-06-27 08:29:03 +02:00
Stian Thorgersen b4470165c7 Merge pull request #4257 from stianst/KEYCLOAK-4891
KEYCLOAK-4891 Add keycloak-api-docs-dist to mvn repo in prod profile
2017-06-27 07:39:54 +02:00
Stian Thorgersen af63fcbc4d KEYCLOAK-4891 Add keycloak-api-docs-dist to mvn repo in prod profile 2017-06-26 19:54:33 +02:00
Bill Burke d77824ff98 Merge pull request #4256 from patriot1burke/master
KEYCLOAK-3444 KEYCLOAK-528
2017-06-26 13:27:08 -04:00
Bill Burke b771960e21 fix log file 2017-06-26 12:36:43 -04:00
Bill Burke bc05560d4d Merge remote-tracking branch 'upstream/master' 2017-06-26 11:41:12 -04:00
Bill Burke 3855b5c0a3 admin console work 2017-06-26 11:40:56 -04:00
Bill Burke 28b3ef9aa9 admin console work 2017-06-26 11:40:32 -04:00
Bill Burke 22987bb90b Merge pull request #4250 from mposolda/RHSSO-1027
KEYCLOAK-5085 Easy fix to just handle the exception
2017-06-26 10:04:02 -04:00
Stian Thorgersen 1c10199698 Merge pull request #4252 from hmlnarik/KEYCLOAK-5078-ConcurrencyTest-fails-intermittently
KEYCLOAK-5078 ConcurrencyTest fails intermittently
2017-06-26 12:48:37 +02:00
Stian Thorgersen 4367f03304 Merge pull request #4254 from hmlnarik/KEYCLOAK-5030-Action-Tokens-do-not-initialize-invalidation-cache-on-start
KEYCLOAK-5030 Change action tokens cache type to distributed
2017-06-26 12:41:02 +02:00
Hynek Mlnarik 955cbc76d7 KEYCLOAK-5030 Change action tokens cache type to distributed 2017-06-26 10:11:53 +02:00
Bill Burke f1807aead4 impersonate 2017-06-25 11:28:37 -04:00
mposolda 756d996a4a KEYCLOAK-5085 RHSSO-1027 Fix to handle the exception thrown from alternative flow 2017-06-23 19:13:43 +02:00
Bill Burke 3ee86fedc7 Merge remote-tracking branch 'upstream/master' 2017-06-23 09:57:35 -04:00
Bill Burke e7f781df5a fix 2017-06-23 09:57:25 -04:00
Hynek Mlnarik 8f9ed32a66 KEYCLOAK-5078 ConcurrencyTest fails intermittently
This commit fixes 401 Unauthorized issues
2017-06-23 15:16:23 +02:00
Bill Burke 39dea4b078 restricting admin role mapping 2017-06-22 16:51:46 -04:00
Pavel Drozd 58e5f41415 Merge pull request #4210 from vramik/KEYCLOAK-4983
KEYCLOAK-4983 export authorization test with multiple roles
2017-06-22 09:36:26 +02:00
Pavel Drozd a7fbcaaef4 Merge pull request #4211 from vramik/KEYCLOAK-5027
KEYCLOAK-5027 Add possibility to attach debugger to jboss based servers
2017-06-22 09:34:58 +02:00
vramik e75f47d523 KEYCLOAK-5048 missing keycloak version in logs when staring auth-server-wildfly container. 2017-06-22 09:20:11 +02:00
Stian Thorgersen cc14c5db23 Merge pull request #4239 from frelibert/KEYCLOAK-4897
KEYCLOAK-4897 SAML Adapter fails to validate signature on assertion
2017-06-22 08:45:04 +02:00
Stian Thorgersen 6f731dfee9 Merge pull request #4118 from skjolber/feature/KEYCLOAK-3056-verify-signature-2
Some adjustments for KEYCLOAK-3056 / PR #3893
2017-06-22 08:44:32 +02:00
Marek Posolda ab7a0c2252 Merge pull request #4248 from mposolda/client-initial-access-db
KEYCLOAK-4631 Move ClientInitialAccessModel from userSession model to…
2017-06-22 06:27:25 +02:00
Bill Burke d08ddade2e merge 2017-06-21 17:43:54 -04:00
Bill Burke 52e40922bc removal 2017-06-21 17:42:57 -04:00
Bill Burke 2b1613d36b Merge pull request #4064 from frelibert/KEYCLOAK-4781
KEYCLOAK-4781 Support for an AttributeStatement Mapper
2017-06-21 17:06:16 -04:00
Bill Burke f1132ffabe Merge pull request #4175 from mrezai/fix-pkce-s256-code-challenge
KEYCLOAK-4956: Fix incorrect PKCE S256 code challenge generation
2017-06-21 17:04:31 -04:00
Bill Burke 8c82201add Merge pull request #4224 from pedroigor/KEYCLOAK-3168
[KEYCLOAK-3168] - Group-Based Access Control
2017-06-21 17:03:34 -04:00
mposolda fc61a4e89f KEYCLOAK-4631 Move ClientInitialAccessModel from userSession model to realm model 2017-06-21 22:14:20 +02:00
Marek Posolda f289771fd3 Merge pull request #4246 from hmlnarik/KEYCLOAK-4993-Intermittent-failures-in-ComponentsTest-testConcurrencyWithChildren
KEYCLOAK-4993 Fix intermittent failures in ComponentsTest testConcurrencyWithChildren
2017-06-21 22:14:00 +02:00
Pedro Igor 8676148f20 Merge pull request #4244 from pedroigor/master
[KEYCLOAK-5702] - Caching scripts and removing when updating
2017-06-21 16:19:36 -03:00
Hynek Mlnarik bf43ccf6c1 KEYCLOAK-4993 Fix intermittent failures in ComponentsTest testConcurrencyWithChildren
... and seems that the KEYCLOAK-5020 as well
2017-06-21 15:19:23 +02:00
Hisanobu Okuda eebd3feb28 fix email messages in Japanese 2017-06-21 21:42:14 +09:00
Marek Posolda be5291f710 Merge pull request #4242 from mposolda/master
KEYCLOAK-4438 Disable kerberos flow when provider removed
2017-06-21 11:54:50 +02:00
Marek Posolda 3fd6fc250d Merge pull request #4240 from hmlnarik/KEYCLOAK-4189-Cross-DC-testing
KEYCLOAK-4189 Infinispan cache and channel statistics for Cross-DC testing
2017-06-21 10:22:43 +02:00
mposolda e91dd011c5 KEYCLOAK-4438 Disable kerberos flow when provider removed 2017-06-21 09:38:20 +02:00
Stian Thorgersen 8e36a52f1e Merge pull request #4227 from sebastienblanc/KEYCLOAK-3492-rebased
KEYCLOAK-3492 : Changing request matcher to attempt auth on /sso/login or Auhtorizati…
2017-06-21 08:51:09 +02:00
Stian Thorgersen 9edb5b53c0 Merge pull request #4199 from guigarage/spring-security-annotation
Easy Spring security annotation
2017-06-21 08:47:17 +02:00
Marek Posolda eae0360eb1 Merge pull request #4243 from mposolda/KEYCLOAK-3316
KEYCLOAK-3316 Fixes for OAuth2 requests without 'scope=openid'
2017-06-20 22:05:23 +02:00
Pedro Igor c7a20d7620 [KEYCLOAK-5702] - Caching scripts and removing when updating 2017-06-20 15:26:18 -03:00
Pedro Igor 93d57c7d00 Merge pull request #4236 from CoreFiling/js-policy-performance
[KEYCLOAK-5072] - Improve performance of JSPolicyProvider
2017-06-20 15:11:40 -03:00
mposolda 32cf8b7cad KEYCLOAK-3316 Fixes for OAuth2 requests without 'scope=openid' 2017-06-20 17:17:43 +02:00
Marek Posolda 88d9411f4d Merge pull request #4241 from mposolda/master
KEYCLOAK-4327 Switching language on User consent gives error
2017-06-20 14:01:09 +02:00
Hynek Mlnarik 2e2d15be9f KEYCLOAK-4189 Infinispan cache and channel statistics for Cross-DC-testing 2017-06-20 12:48:08 +02:00
mposolda f363dbcad0 KEYCLOAK-4327 Switching language on User consent gives error 2017-06-20 09:21:41 +02:00
Frederik Libert 63d2d0f7ed KEYCLOAK-4897 SAML Adapter fails to validate signature on assertion 2017-06-19 18:26:17 +02:00
Jay Anslow a04d79c576 Cache compiled scripts in JSPolicyProviderFactory 2017-06-19 16:53:07 +01:00
Bill Burke 57cb46148f tests 2017-06-19 11:21:59 -04:00
Jay Anslow 7614ff8c6f Extract EvaluatebleScriptAdapter
Precursor for InvocableScriptAdapter, which compiles/evaluates a script without affecting the engine's bindings. This allows the same script to be compiled once and then evaluated multiple times (with the same ScriptEngine).
2017-06-19 15:32:14 +01:00
Marek Posolda edc6d99c9c Merge pull request #4230 from vramik/KEYCLOAK-4189
KEYCLOAK-4189 add possibility to use JDG as a cache server
2017-06-19 11:06:42 +02:00
Bill Burke a994af9010 remove scope 2017-06-16 11:26:43 -04:00
Pedro Igor 0b5e6b0d49 JS policy should use ScriptingSPI 2017-06-16 11:49:32 -03:00
Pedro Igor 222541ab5c Merge pull request #4228 from pedroigor/KEYCLOAK-5054
[KEYCLOAK-5054] - Checking name availability only in cases name is filled
2017-06-16 10:30:44 -03:00
vramik dfed148921 KEYCLOAK-4189 fixed issue with exlude cross DC tests by default 2017-06-16 11:32:02 +02:00
Samuel Mangot a785f9fd11 Email - I18n - added missing german text 2017-06-16 09:55:54 +02:00
Pedro Igor 93105a2182 [KEYCLOAK-5056] - @NoCache to scope admin api 2017-06-15 09:49:20 -03:00
Hendrik Ebbers 0ac92c4bfa new line in doc 2017-06-15 13:01:05 +02:00
Hendrik Ebbers 98a5c57e65 Author added 2017-06-15 13:00:24 +02:00
vramik 5d72def1bc KEYCLOAK-4189 add possibility to use jdg as cache server 2017-06-15 12:57:25 +02:00
Stian Thorgersen f0d1149311 Merge pull request #4217 from stianst/KEYCLOAK-5044
KEYCLOAK-5044 Remove Angular2 example2
2017-06-15 12:05:11 +02:00
Pedro Igor d4a85d6abc [KEYCLOAK-5054] - Checking name availability only in cases name is filled 2017-06-14 18:10:51 -03:00
Marek Posolda a34f890453 Merge pull request #4223 from hmlnarik/KEYCLOAK-4189-Cross-DC-testing
KEYCLOAK-4189 Fix in instructions for running Cross-DC tests
2017-06-14 21:11:18 +02:00
Marek Posolda f8999128dc Merge pull request #4226 from TeliaSoneraNorge/KEYCLOAK-4924
KEYCLOAK-4924 pairwise clients get duplicate subs in tokens
2017-06-14 15:01:09 +02:00
emilienbondu 91585f8563 Changing request matcher to attempt auth on /sso/login or Auhtorization header
Add default login URL.

Throwing exception if login fails to enable auth entry point

Adding a test for invalid token and bearer-only

handle redirect correctly
2017-06-14 14:41:35 +02:00
Hynek Mlnarik bdadef1282 KEYCLOAK-4189 Fix in instructions for running Cross-DC tests 2017-06-14 14:36:10 +02:00
Pedro Igor 5028c05cc2 [KEYCLOAK-3168] - Export and import tests 2017-06-14 09:33:59 -03:00
Pedro Igor 6202222da4 Merge pull request #4221 from pedroigor/KEYCLOAK-5051
[KEYCLOAK-5051] - Invalidate authz cache when realm cache is cleared
2017-06-14 07:53:46 -03:00
Martin Hardselius 60942346f3 KEYCLOAK-4924: pairwise clients get duplicate subs in tokens 2017-06-14 10:47:40 +02:00
vramik 97509ebf89 KEYCLOAK-4983 export authorization test with multiple roles 2017-06-14 10:38:47 +02:00
Pedro Igor 169280b6a1 [KEYCLOAK-3168] - Group-Based Access Control 2017-06-13 19:05:44 -03:00
Vaclav Muzikar 35857bf649 KEYCLOAK-5055 Stabilize UI tests 2017-06-13 11:24:45 +02:00
Marek Posolda bc407a7968 Merge pull request #4212 from hmlnarik/KEYCLOAK-4189-Cross-DC-testing
KEYCLOAK-4189 - Cross DC testing
2017-06-12 18:09:44 +02:00
Pedro Igor 473065fd31 [KEYCLOAK-5051] - Invalidate authz cache when realm cache is cleared 2017-06-12 12:29:21 -03:00
Hynek Mlnarik a0f3a6469f KEYCLOAK-4189 - Cross DC testing 2017-06-12 11:14:28 +02:00
Pedro Igor fd8a3dccaf Merge pull request #4214 from pedroigor/KEYCLOAK-4904
[KEYCLOAK-4904] - Authorization Audit - Part 1
2017-06-09 17:17:30 -03:00
Pedro Igor f12cef2c86 [KEYCLOAK-4904] - Authorization Audit - Part 1 2017-06-09 13:31:06 -03:00
Pedro Igor 2b55cd7902 Merge pull request #4213 from pedroigor/cache-fixes
Missing invalidation for some queries cache
2017-06-09 09:13:13 -03:00
Stian Thorgersen a9b9d16500 KEYCLOAK-5044 Remove Angular2 example2 2017-06-09 13:43:32 +02:00
Machiel Keizer-Groeneveld 80f8815b9a KEYCLOAK-5026 Store credentials
Credentials are stored with user creation if they are present in the UserRepresentation.
2017-06-09 09:32:33 +02:00
Stian Thorgersen 6cccd66162 Merge pull request #4192 from hokuda/KEYCLOAK-4980
KEYCLOAK-4980 SAML adapter should return 403 when unauthenticated Aja…
2017-06-09 04:40:26 +02:00
Pedro Igor 84d2d7b431 Missing invalidation for some queries cache 2017-06-08 18:09:44 -03:00
Hisanobu Okuda 9135ba7c40 KEYCLOAK-4980 SAML adapter should return 401 when unauthenticated Ajax client accesses 2017-06-08 23:36:25 +09:00
Bill Burke 94528976d4 console work 2017-06-07 16:29:43 -04:00
vramik 7381ec456a KEYCLOAK-5027 Add possibility to attach debugger to jboss based servers 2017-06-07 14:35:33 +02:00
Bill Burke 536a57a514 ui for permission reference 2017-06-05 19:52:51 -04:00
Alex Szczuczko 5d88c2b8be KEYCLOAK-4758 Update Encode class using latest resteasy. Use encodeQueryParamAsIs instead of encodeQueryParam when encoding key=value pairs for URI query sections. Also fix a few callers who were relying on the bad behaviour of queryParam. 2017-06-05 16:24:38 -06:00
Pedro Igor 9be9e30ad6 Merge pull request #4206 from pedroigor/KEYCLOAK-4983
[KEYCLOAK-4983] - Authz settings export of role base policy generates json where are just role-names
2017-06-05 16:19:58 -03:00
Pedro Igor 40c4140021 Merge pull request #4198 from pedroigor/KEYCLOAK-4992
RFEs based on Openshift.io authz requirements
2017-06-05 16:03:50 -03:00
Pedro Igor 23887f4031 Fixing tests and more client policy tests 2017-06-05 11:26:33 -03:00
Pedro Igor 3760f2753b [KEYCLOAK-4983] - Authz settings export of role base policy generates json where are just role-names 2017-06-02 20:09:33 -03:00
Pedro Igor d0f505455d [KEYCLOAK-4991] - Allow clients to limit the number of permission in a RPT when using entitlements 2017-06-02 19:06:40 -03:00
Bill Burke a41d282e92 client permission tests 2017-06-02 15:49:20 -04:00
Pedro Igor 813af5d757 [KEYCLOAK-4992] - Using query parameter metadata for GET requests 2017-06-02 16:13:04 -03:00
Thomas Skjølberg 241c58dd61 Add unit tests related to signatures, check that a signature is present when want assertion signing. 2017-06-02 15:36:52 +02:00
Pedro Igor 1cddaeb707 Merge pull request #4203 from pedroigor/master
[KEYCLOAK-4932] - Improvements to policy enforcer and better spring boot support
2017-06-02 10:31:10 -03:00
Pedro Igor d69d00082f [KEYCLOAK-4932] - Improvements to policy enforcer and better spring boot support 2017-06-01 22:55:58 -03:00
Bill Burke b9f7a43a72 group permissions 2017-06-01 20:16:35 -04:00
Alex Szczuczko bed6f96fc6 KEYCLOAK-4752 Change required actions UI to uncheck and disable the default checkbox when the enable checkbox is not checked. The API will continue to silently drop actions that are not enabled for the realm. 2017-06-01 08:25:51 -06:00
Hendrik Ebbers 4d5e03049e provide a custom KeycloakConfigResolver instance for servlet filter. 2017-06-01 14:35:12 +02:00
Hendrik Ebbers 7d017b4edf Easy Spring security annotation 2017-06-01 12:05:02 +02:00
Pedro Igor dcd1a68d95 [KEYCLOAK-4992] - Allow clients to exclude resource_set_name from RPT 2017-05-31 19:33:34 -03:00
Pedro Igor b71bb96540 Merge pull request #4197 from pedroigor/KEYCLOAK-4987
[KEYCLOAK-4987] - Remove async support from AuthZ Token Endpoints
2017-05-30 12:49:19 -03:00
Pedro Igor c4a0470a37 [KEYCLOAK-4987] - Remove async support from AuthZ Token Endpoints 2017-05-30 12:48:18 -03:00
Pavel Drozd a52a1f4618 Merge pull request #4196 from vramik/KEYCLOAK-4481
KEYCLOAK-4481 some authz export tests
2017-05-30 16:56:54 +02:00
Pavel Drozd a2e35bf711 Merge pull request #4186 from tkyjovsk/KEYCLOAK-4970
KEYCLOAK-4970 Arquillian testsuite doesn't work with -Pauth-server-wildfly after upgrade to WF11
2017-05-30 16:55:21 +02:00
Stian Thorgersen a6e4245185 Merge pull request #4194 from stianst/KEYCLOAK-4888
KEYCLOAK-4888
2017-05-30 14:49:22 +02:00
Tomas Kyjovsky 67bee0dfc2 Upgraded wildfly-arquillian-container-* artifacts to 2.1.0.Alpha2 and added wildfly10 modules in app servers and adapter tests 2017-05-30 14:25:51 +02:00
vramik 8f1938c28d KEYCLOAK-4481 Role based permission test 2017-05-30 13:10:09 +02:00
Stian Thorgersen a15517c5ce Merge pull request #4195 from mstruk/KEYCLOAK-4974
KEYCLOAK-4974 Can not run tests against PNC build
2017-05-30 12:57:09 +02:00
Marko Strukelj af6f617e0e KEYCLOAK-4974 Can not run tests against PNC build 2017-05-30 11:54:42 +02:00
Stian Thorgersen 8c53c5a90e KEYCLOAK-4888
Change default hashing provider for realm
2017-05-30 09:54:05 +02:00
Marek Posolda ca4488a845 Merge pull request #4193 from thomasdarimont/issue/KEYCLOAK-4975-fix-session-binding-in-scriptbasedauthenticator
KEYCLOAK-4975 Use authenticationSession binding name in ScriptBasedAuthenticator
2017-05-30 07:53:24 +02:00
Thomas Darimont 7d0b461683 KEYCLOAK-4975 Use authenticationSession binding name in ScriptBasedAuthenticator
We now use authenticationSession instead of clientSession to reflect
the renaming of ClientSessionModel to AuthenticationSessionModel.

Note that this is a breaking change which needs to be mentioned in
the upgrade notes!
2017-05-29 18:14:02 +02:00
Bill Burke c3ea847b3e auth changes 2017-05-29 09:53:17 -04:00
Stian Thorgersen 684689d40d Merge pull request #3561 from glavoie/KEYCLOAK-3990
KEYCLOAK-3990: Very slow use of NamedQueries.
2017-05-29 09:39:39 +02:00
Marek Posolda c47952250d Merge pull request #4189 from mposolda/master
KEYCLOAK-4977 Upgrade infinispan and undertow version to align with W…
2017-05-26 15:22:14 +02:00
mposolda c4f172afe7 KEYCLOAK-4977 Upgrade infinispan and undertow version to align with Wildfly 11.0.0.Alpha1 2017-05-26 14:29:30 +02:00
Marek Posolda c43329d033 Merge pull request #4188 from mposolda/master
KEYCLOAK-4626 Changed javadoc. Remove unused ClientSessionModel class
2017-05-25 21:52:01 +02:00
mposolda 5560175888 KEYCLOAK-4626 Changed javadoc. Remove unused ClientSessionModel class 2017-05-25 18:51:05 +02:00
Pavel Drozd bb1096c511 Merge pull request #4182 from mhajas/KEYCLOAK-4959
KEYCLOAK-4959 Use desired version of adapter
2017-05-25 13:16:41 +02:00
mhajas 88473ce3c1 KEYCLOAK-4959 Use desired version of adapter 2017-05-25 12:02:16 +02:00
Pedro Igor 81f1a5b145 Merge pull request #4183 from pedroigor/stan-ui-fixes
[KEYCLOAK-4915] - Fixes to evaluation tool UI
2017-05-24 09:32:42 -03:00
Hynek Mlnarik e4fc8f083e KEYCLOAK-3990 Tests 2017-05-24 07:50:48 -04:00
Marek Posolda 79af4dfd18 Merge pull request #4127 from sbryzak/KEYCLOAK-4886
KEYCLOAK-4886
2017-05-24 10:47:09 +02:00
Marek Posolda 9e509d71d2 Merge pull request #4184 from mposolda/master
KEYCLOAK-3316 Remove the IDToken if scope=openid is not used
2017-05-24 10:45:43 +02:00
mposolda 2b59db71a8 KEYCLOAK-3316 Remove the IDToken if scope=openid is not used 2017-05-24 09:23:14 +02:00
Stian Thorgersen 63c237423d Merge pull request #4098 from ahus1/KEYCLOAK-4814-disable-keycloak-spring-boot-by-configuration
KEYCLOAK-4814 disable keycloak spring boot by configuration
2017-05-24 07:12:05 +02:00
Stian Thorgersen b870e81648 Merge pull request #4176 from abstractj/KEYCLOAK-4869
[KEYCLOAK-4869] Integration tests for app-html5 are failing after upgrade to 3.1.0.Final
2017-05-24 06:59:37 +02:00
Stian Thorgersen 03308d8b20 Merge pull request #4179 from hmlnarik/KEYCLOAK-4790-Empty-attribute-value-problem-in-KC-SAML-parser
KEYCLOAK-4790 Fix empty attribute value issue in SAML parser
2017-05-24 06:48:12 +02:00
Pavel Drozd 73c328d5e3 Merge pull request #4178 from pdrozd/ldap-import-test
KEYCLOAK-4958 Fix condition for skipping test
2017-05-24 00:32:22 +02:00
Pedro Igor 829bcf5eaf Fix to evaluation tool 2017-05-23 17:50:06 -03:00
Pedro Igor 554e692d8f Merge pull request #4171 from pedroigor/KEYCLOAK-4913
[KEYCLOAK-4913] - Caching more query methods
2017-05-23 17:40:51 -03:00
Pedro Igor 366cb78a36 Merge pull request #4156 from pedroigor/master
Keycloak Authz Client dependency to adapter BOM
2017-05-23 16:19:08 -03:00
Pedro Igor 1d5bd2567e [KEYCLOAK-4913] - Caching more query methods 2017-05-23 16:13:20 -03:00
Hynek Mlnarik 67a05ee227 KEYCLOAK-4790 Fix empty attribute value issue in SAML parser 2017-05-23 15:14:25 +02:00
Pavel Drozd a9c98a577b KEYCLOAK-4958 Fix condition for skipping test 2017-05-23 14:47:14 +02:00
Stian Thorgersen c442bcd8d3 Merge pull request #4174 from stianst/KEYCLOAK-4889
KEYCLOAK-4889
2017-05-23 14:26:15 +02:00
Stian Thorgersen c00a64208a Merge pull request #4136 from frelibert/KEYCLOAK-4897
KEYCLOAK-4897
2017-05-23 14:10:34 +02:00
Gabriel Lavoie e59aeb56cc KEYCLOAK-3990: Very slow use of NamedQueries.
- Generates too many auto-flush checks by Hibernate.
- Moved to collections mapping to allow batching and the use of Hibernate L2 cache.
2017-05-23 08:09:39 -04:00
Stian Thorgersen e3a04ebd90 Merge pull request #3557 from glavoie/KEYCLOAK-3988
KEYCLOAK-3988: Multiple missing indexes on FKs.
2017-05-23 14:07:51 +02:00
Pavel Drozd 06152d9883 Merge pull request #4165 from vmuzikar/google-fix
KEYCLOAK-4944 Fix SocialLoginTest to reflect new Google Login screen
2017-05-23 14:03:08 +02:00
Pavel Drozd c230edbf72 Merge pull request #4151 from pdrozd/KEYCLOAK-4931
KEYCLOAK-4931 - install patch available from http
2017-05-23 14:01:44 +02:00
Stian Thorgersen 1b6405a28f Merge pull request #4173 from hmlnarik/KEYCLOAK-4941
KEYCLOAK-4941
2017-05-23 14:00:43 +02:00
Pavel Drozd 12fec09410 Merge pull request #4150 from pdrozd/KEYCLOAK-4930
KEYCLOAK-4930 - Updated install-keycloak script for overlay installat…
2017-05-23 14:00:35 +02:00
Stian Thorgersen ef29097679 Merge pull request #4172 from hmlnarik/KEYCLOAK-4813-Destination-Validation-should-ignore-whether-default-port-is-explicitly-specified
KEYCLOAK-4813 Destination validation counts on port being not specified
2017-05-23 13:59:36 +02:00
Pavel Drozd 0a869f56a7 Merge pull request #4146 from vramik/KEYCLOAK-4926
KEYCLOAK-4926 exclude WelcomePageTest from migration scenario
2017-05-23 13:59:26 +02:00
Stian Thorgersen cd53486566 Merge pull request #4167 from sebastienblanc/bug-KEYCLOAK-3492
Fix https://issues.jboss.org/browse/KEYCLOAK-3492
2017-05-23 13:58:19 +02:00
Stian Thorgersen ff2d6941d0 Merge pull request #4140 from mstruk/RHSSO-978
RHSSO-978 Cannot migrate event types using export/import
2017-05-23 13:55:17 +02:00
Mohammad Rezai acd78ee407 KEYCLOAK-4956: Fix incorrect PKCE S256 code challenge generation 2017-05-23 16:15:44 +04:30
Stian Thorgersen 130452f6c3 Merge pull request #4085 from mstruk/RHSSO-402
RHSSO-402 need a way to dump configuration (including ldap provider config) to a file
2017-05-23 13:29:32 +02:00
Stian Thorgersen 178fd08d9a Merge pull request #4066 from johnament/KEYCLOAK-4765
KEYCLOAK-4765 - Add ability to disable Query Parameter parsing.
2017-05-23 13:24:08 +02:00
Stian Thorgersen 097a2267f5 KEYCLOAK-4889
Improve error messages for password policies
2017-05-23 13:18:06 +02:00
Bruno Oliveira 7afdd98499 [KEYCLOAK-4869] Integration tests for app-html5 are failing after upgrade to 3.1.0.Final 2017-05-23 08:02:29 -03:00
Hynek Mlnarik f47283f61a KEYCLOAK-4813 Destination validation counts on port being not specified 2017-05-23 12:52:48 +02:00
Hynek Mlnarik 03b1dff1bd KEYCLOAK-4941 2017-05-23 11:15:51 +02:00
Marek Posolda 804766827c Merge pull request #4170 from mposolda/KEYCLOAK-4016_backToAppLink
KEYCLOAK-4016 Provide a Link to go Back to The Application on a Timeout
2017-05-23 09:53:16 +02:00
mposolda 8adde64e2c KEYCLOAK-4016 Provide a Link to go Back to The Application on a Timeout 2017-05-23 09:08:58 +02:00
Stian Thorgersen ca8577fb4a Merge pull request #4169 from NetForce1/KEYCLOAK-4911
KEYCLOAK-4911 charset not specified by Java client registration API
2017-05-23 08:20:38 +02:00
Pedro Igor 37a98fba20 [KEYCLOAK-4913] - Caching more query methods 2017-05-22 19:08:24 -03:00
Daan de Wit ef6b303bfe KEYCLOAK-4911 charset not specified by Java client registration API 2017-05-22 15:22:39 +02:00
Pedro Igor 8d40ee17f1 Merge pull request #4166 from pedroigor/stan-ui-fixes
[EYCLOAK-4915] - Review AuthZ UIs
2017-05-22 10:10:09 -03:00
Stian Thorgersen 29c5d683d0 Merge pull request #4164 from abacusresearch/KEYCLOAK-4940_typo_in_German_email_verification_body
KEYCLOAK-4940 Fix typo in German email verification body
2017-05-22 10:33:05 +02:00
emilienbondu 3580dea399 Fix https://issues.jboss.org/browse/KEYCLOAK-3492 2017-05-22 10:18:22 +02:00
Pedro Igor 7ae117707b Fixing validation of required fields 2017-05-19 19:45:47 -03:00
Pedro Igor d1d590b45c Delete action on lists 2017-05-19 19:45:47 -03:00
Pedro Igor 62ffab7239 Exporting a client is updating policy config 2017-05-19 19:45:47 -03:00
Pedro Igor 7681c76ee1 Keycloak AuthZ Client as spring-boot-starter dependency 2017-05-19 17:15:22 -03:00
Bill Burke ab763e7c5b fixes after merge 2017-05-19 15:54:36 -04:00
Vaclav Muzikar c2379dbe49 KEYCLOAK-4944 Fix SocialLoginTest to reflect new Google Login screen 2017-05-19 18:07:05 +02:00
Bill Burke f114895cd2 for merge 2017-05-19 11:29:26 -04:00
Marek Posolda ce9320755d Merge pull request #4163 from mposolda/master
KEYCLOAK-4939 ConcurrentLoginTest broken in latest master
2017-05-19 17:26:39 +02:00
Dominik Langenegger dce4353e0d KEYCLOAK-4940 Fix typo in German email verification body 2017-05-19 14:26:40 +02:00
Marek Posolda 4d5ca2b8fa Merge pull request #4159 from hmlnarik/KEYCLOAK-4627-Nicer-text-in-html-email
KEYCLOAK-4627 Nicer link texts in HTML variant of emails
2017-05-19 14:03:39 +02:00
Marek Posolda 8e4899f874 Merge pull request #4158 from hmlnarik/KEYCLOAK-4627-Change-wording
KEYCLOAK-4627 Change wording of the configuration in UI
2017-05-19 14:03:24 +02:00
mposolda e2a7b71cf3 KEYCLOAK-4939 ConcurrentLoginTest broken in latest master 2017-05-19 14:00:52 +02:00
vramik f0386d9374 KEYCLOAK-4926 exclude WelcomePageTest from migration scenario 2017-05-19 13:30:01 +02:00
Stian Thorgersen 336d05dd34 Merge pull request #4157 from stianst/DIST-UPDATES
Dist updates
2017-05-19 12:22:11 +02:00
Marek Posolda d80381ec0d Merge pull request #4139 from vramik/KEYCLOAK-4827
KEYCLOAK-4827 Add tests for concurrent use of user session in cache
2017-05-19 11:14:57 +02:00
Hynek Mlnarik d4f870fbb4 KEYCLOAK-4627 Nicer link texts in HTML variant of emails 2017-05-19 10:08:02 +02:00
Stian Thorgersen 0b6c9aa927 KEYCLOAK-4723
Refactor service dependencies for caches in KeycloakServerDeploymentProcessor
2017-05-19 09:43:15 +02:00
Hynek Mlnarik ca8d756c05 KEYCLOAK-4627 Change wording of the configuration in UI 2017-05-19 09:39:58 +02:00
Stian Thorgersen a2af516df7 KEYCLOAK-4855
[RHSSO] Compilation issues with Bouncycastle 1.56
2017-05-19 09:37:32 +02:00
Stian Thorgersen 43a625db28 KEYCLOAK-4477 Fix update to WF 11 2017-05-19 08:31:29 +02:00
Stian Thorgersen cc42ea9332 KEYCLOAK-4773 Remove 'providers' directory 2017-05-19 06:24:58 +02:00
Stian Thorgersen 9ec3a8c3d9 KEYCLOAK-4933 Fixes 2017-05-19 06:24:58 +02:00
Stian Thorgersen 2e83eda172 KEYCLOAK-4477 Update to WildFly 11 2017-05-19 06:24:58 +02:00
Stian Thorgersen 6d8a3f7a8b KEYCLOAK-4933 Fixes 2017-05-19 06:24:58 +02:00
Bob McWhirter 56d68c17f5 KEYCLOAK-4933
Use a newer version of the server-provisioning-plugin.

By using a newer version of the plugin, we can reduce
the amount of build code that replicates the provisioning
logic when building overlays.

This applies to both:

* Server distribution overlay
* Adapter distribution overlay

Both overlays are created purely by using the provisioning
plugin and the feature-packs produced elsewhere in the build,
along with the admin-cli artifact when appropriate.
2017-05-19 06:24:58 +02:00
Stian Thorgersen dac848e164 Merge pull request #4142 from stianst/master
KEYCLOAK-4921
2017-05-19 06:15:23 +02:00
Pedro Igor badabf8385 Keycloak Authz Client dependency to adapter BOM 2017-05-18 20:36:16 -03:00
Bill Burke d22a284df1 Merge pull request #4149 from patriot1burke/master
KEYCLOAK-4929
2017-05-18 18:56:03 -04:00
Pavel Drozd 60ef910b5b KEYCLOAK-4931 - install patch available from http 2017-05-18 23:47:12 +02:00
Pavel Drozd 53ab314eb9 KEYCLOAK-4930 - Updated install-keycloak script for overlay installation - added ha installation. 2017-05-18 23:35:04 +02:00
Bill Burke 2cac8b1bb7 KEYCLOAK-4929 2017-05-18 16:53:31 -04:00
Bill Burke c291748f43 KEYCLOAK-4929 2017-05-18 16:48:04 -04:00
Pedro Igor c6ff1037dc Merge pull request #4148 from pedroigor/KEYCLOAK-4927
[KEYCLOAK-4927] - Authz client incompatible with client definition
2017-05-18 14:55:10 -03:00
Pedro Igor b68494b3f0 [KEYCLOAK-4927] - Authz client incompatible with client definition 2017-05-18 09:57:12 -03:00
Marek Posolda 39afd4a020 Merge pull request #4147 from hmlnarik/KEYCLOAK-4627-Action-tokens-theme-typo
KEYCLOAK-4627 Action tokens theme typo
2017-05-18 14:30:41 +02:00
Hynek Mlnarik 355af6d1cf KEYCLOAK-4627 Action tokens theme typo 2017-05-18 14:27:53 +02:00
Marek Posolda 69ada965d8 Merge pull request #4144 from hmlnarik/KEYCLOAK-4187-Action-tokens-additional-tests
KEYCLOAK-4627 Additional tests for action tokens
2017-05-18 14:04:43 +02:00
Hynek Mlnarik f9767ad6cd KEYCLOAK-4627 Additional tests for action tokens 2017-05-18 12:04:32 +02:00
Stian Thorgersen 28acf489a1 KEYCLOAK-4921
add-user-keycloak broken
2017-05-18 09:33:33 +02:00
Marek Posolda 86f95d3f87 Merge pull request #4141 from mposolda/master
KEYCLOAK-4907 Fix postgresql and mssql. Fix migration
2017-05-18 08:41:07 +02:00
mposolda c178a2392d KEYCLOAK-4907 Fix postgresql and mssql. Fix migration 2017-05-17 22:44:44 +02:00
Hynek Mlnarik 10c9e0f00f KEYCLOAK-4897 Tests for assertion-only signatures with encrypted assertions 2017-05-17 15:56:49 +02:00
Frederik Libert 71f0db0837 KEYCLOAK-4897
SAML Adapter fails to validate signature on encrypted assertion.
2017-05-17 15:47:04 +02:00
Marko Strukelj 27b291c345 RHSSO-978 Cannot migrate event types using export/import 2017-05-16 18:52:58 +02:00
Gabriel Lavoie 4581272dcd KEYCLOAK-3988: Multiple missing indexes on FKs. 2017-05-15 08:15:58 -04:00
Marek Posolda 70d7e07526 Merge pull request #4132 from mposolda/cross-dc4-squash
KEYCLOAK-4626 KEYCLOAK-4627 Authentication sessions & Action tokens
2017-05-15 12:46:43 +02:00
Marko Strukelj 7d0ca42c6c RHSSO-402 need a way to dump configuration (including ldap provider config) to a file 2017-05-15 12:13:58 +02:00
Marek Posolda 9804aaf796 Merge pull request #4125 from mtrue01/mtrue01branch
Fixes for ApacheDS
2017-05-15 11:03:24 +02:00
Bill Burke 954ef99f22 Merge remote-tracking branch 'upstream/master' 2017-05-12 10:10:29 -04:00
Bill Burke 789722ec6a Merge pull request #4137 from pedroigor/master
Caching improvements and checking attachments in Elytron adapter
2017-05-12 10:09:44 -04:00
Pedro Igor d824b4d93c Changing cache key for findByResource 2017-05-12 10:25:06 -03:00
Pedro Igor 7569493b17 Invalidating cache for findByowner 2017-05-12 10:23:54 -03:00
Pedro Igor aaddb035a8 Checking if attachments are supported by the underlying container 2017-05-12 10:23:37 -03:00
vramik cc6a5419de KEYCLOAK-4827 Add tests for concurrent use of user session in cache 2017-05-12 14:14:14 +02:00
mposolda 7d8796e614 KEYCLOAK-4626 Support for sticky sessions with AUTH_SESSION_ID cookie. Clustering tests with embedded undertow. Last fixes. 2017-05-11 22:24:07 +02:00
Hynek Mlnarik b8262a9f02 KEYCLOAK-4628 Single-use cache + its functionality incorporated into reset password token. Utilize single-use cache for relevant actions in execute-actions token 2017-05-11 22:16:26 +02:00
mposolda db8b733610 KEYCLOAK-4626 Fix TrustStoreEmailTest and PolicyEvaluationCompositeRoleTest. Distribution update 2017-05-11 22:16:26 +02:00
Hynek Mlnarik c431cc1b01 KEYCLOAK-4627 IdP email account verification + code cleanup. Fix for concurrent access to auth session notes 2017-05-11 22:16:26 +02:00
mposolda 168153c6e7 KEYCLOAK-4626 Authentication sessions - SAML, offline tokens, broker logout and other fixes 2017-05-11 22:16:26 +02:00
Hynek Mlnarik 47aaa5a636 KEYCLOAK-4627 reset credentials and admin e-mails use action tokens. E-mail verification via action tokens. 2017-05-11 22:16:26 +02:00
mposolda e7272dc05a KEYCLOAK-4626 AuthenticationSessions - brokering works. Few other fixes and tests added 2017-05-11 22:16:26 +02:00
Hynek Mlnarik b55b089355 KEYCLOAK-4627 Changes in TokenVerifier to include token in exceptions. Reset credentials uses checks to validate individual token aspects 2017-05-11 22:16:26 +02:00
mposolda a9ec69e424 KEYCLOAK-4626: AuthenticationSessions - working login, registration, resetPassword flows 2017-05-11 22:16:26 +02:00
Hynek Mlnarik 19a41c8704 KEYCLOAK-4627 Refactor TokenVerifier to support more than just access token checks. Action tokens implementation with reset e-mail action converted to AT 2017-05-11 22:16:26 +02:00
mposolda 83b29c5080 KEYCLOAK-4626 AuthenticationSessions: start 2017-05-11 22:16:26 +02:00
Marek Posolda f392e79ad7 Merge pull request #4130 from mposolda/master
KEYCLOAK-4829 Access token from offline token falsely reported as ina…
2017-05-11 21:55:53 +02:00
mposolda e4aba9e471 KEYCLOAK-4829 Access token from offline token falsely reported as inactive by token introspection 2017-05-11 21:17:04 +02:00
Mark True c19d6f36ed KEYCLOAK-4350 fixes test for embedded LDAP for ApacheDS 2017-05-11 09:10:26 -04:00
Stian Thorgersen 14908d9038 Merge pull request #4128 from stianst/KEYCLOAK-4523
KEYCLOAK-4523 PBKDF2WithHmacSHA256 and PBKDF2WithHmacSHA512 providers
2017-05-11 13:35:15 +02:00
Stian Thorgersen c3a2b3a6b6 KEYCLOAK-4523 PBKDF2WithHmacSHA256 and PBKDF2WithHmacSHA512 providers 2017-05-11 11:58:22 +02:00
Stan Silvert 9378ede362 Merge pull request #4126 from ssilvert/def-typed
KEYCLOAK-4822: Update types to be ES6 compatible
2017-05-10 20:43:00 -04:00
Shane Bryzak 349a59cf35 KEYCLOAK-4886 update Openshift view template to allow setting an alias and display name
Signed-off-by: Shane Bryzak <sbryzak@redhat.com>
2017-05-11 09:27:49 +10:00
Stan Silvert 64cd689e38 KEYCLOAK-4822: Change copyright to reflect correct author. 2017-05-10 16:32:05 -04:00
Bill Burke bfb4395b28 role and Users finished UI work 2017-05-10 15:25:04 -04:00
Bill Burke 46ec12c41c fixes 2017-05-10 14:19:10 -04:00
Pedro Igor 0d9ffd4e64 Merge pull request #4122 from pedroigor/master
Test for role policy evaluation
2017-05-10 10:03:29 -03:00
Stian Thorgersen d39d39a8eb Merge pull request #4123 from knutz3n/KEYCLOAK-4875
KEYCLOAK-4875 Use realm name to generate configuration url
2017-05-10 06:44:05 +02:00
Johannes Knutsen b64817761a KEYCLOAK-4875 Use realm name instead of realm id to generate OpenID Endpoint Configuration URL in admin's Realm Settings page 2017-05-09 22:05:10 +02:00
Stian Thorgersen f3febd1067 Merge pull request #4121 from stianst/KEYCLOAK-4873
Keycloak 4873
2017-05-09 20:46:21 +02:00
Pedro Igor ec53af29c5 Merge pull request #4117 from pedroigor/KEYCLOAK-4867
[KEYCLOAK-4867] - Cluster events and invalidations
2017-05-09 15:27:46 -03:00
Pedro Igor c0b08a27a2 Test for role policy evaluation 2017-05-09 15:27:19 -03:00
Stian Thorgersen 18295497ae Bump RH-SSO version to 7.2.0.DR3 2017-05-09 19:44:37 +02:00
Pedro Igor 978619ead0 [KEYCLOAK-4867] - Missing cache config in server overlay 2017-05-09 14:21:06 -03:00
Stian Thorgersen 12e56086d5 KEYCLOAK-4873
product.version property should refer to product version
2017-05-09 19:17:42 +02:00
Bill Burke a8a8ea4bcd Merge remote-tracking branch 'upstream/master' 2017-05-08 13:49:03 -04:00
Bill Burke f760427c5c fine grain tests 2017-05-08 13:48:51 -04:00
Stian Thorgersen 126830cd8b Merge pull request #4120 from stianst/KEYCLOAK-4870
Fix readme
2017-05-08 15:40:43 +02:00
Stian Thorgersen e738b84fd5 Fix readme 2017-05-08 15:39:23 +02:00
Stian Thorgersen 59d5604699 Merge pull request #4119 from stianst/KEYCLOAK-4870
KEYCLOAK-4870
2017-05-08 15:37:51 +02:00
Stian Thorgersen 68c7da141b Fix 2017-05-08 15:14:55 +02:00
Stian Thorgersen f63c60855e Fix compilation error in SAMLParserTest.java 2017-05-08 14:45:45 +02:00
Stian Thorgersen f0a0b553e5 KEYCLOAK-4870
Travis doesn't run unit tests
2017-05-08 14:35:17 +02:00
Pedro Igor e14be4460b [KEYCLOAK-4867] - Cluster events and invalidations 2017-05-05 22:48:51 -03:00
Stan Silvert 2d825dd366 KEYCLOAK-4822: Update to ES6-compatible typings 2017-05-05 15:08:23 -04:00
Stian Thorgersen f4f9a98e70 Merge pull request #4114 from knutz3n/KEYCLOAK-4862
KEYCLOAK-4862: Expose client description in ClientBean
2017-05-05 15:43:38 +02:00
Johannes Knutsen 47a8077426 KEYCLOAK-4862: Expose client description in ClientBean 2017-05-05 15:06:21 +02:00
Bill Burke e1b6ba13cc Merge pull request #3893 from anderius/feature/KEYCLOAK-3056-verify-signature
[WIP] Saml broker: Added wantAssertionsSigned and wantAssertionsEncrypted
2017-05-05 09:04:41 -04:00
Stian Thorgersen 8da766e02e Merge pull request #4104 from sjvs/master
Fix three lgtm.com alerts: two possible NPEs, one possible int overflow
2017-05-05 13:13:02 +02:00
Pavel Drozd a8071356bb Merge pull request #4109 from mhajas/KEYCLOAK-4503
KEYCLOAK-4503 Add test
2017-05-05 13:06:50 +02:00
Pavel Drozd ec5860d7f5 Merge pull request #4102 from mhajas/KEYCLOAK-4650
KEYCLOAK-4650 Add cancel warning test
2017-05-05 13:06:03 +02:00
Stian Thorgersen 7c2fcaf141 Merge pull request #4113 from stianst/master
Fixes for product build
2017-05-05 12:55:33 +02:00
Stian Thorgersen e0da7ed6b4 Merge pull request #4074 from sebastienblanc/allow_headers
Keycloak-3297 : adding cors-exposed-headers to conf
2017-05-05 12:54:47 +02:00
Marek Posolda 5e1654658f Merge pull request #4112 from r0nin/master
KEYCLOAK-4521: consider offline sessions if no active user session exists
2017-05-05 12:13:09 +02:00
Stian Thorgersen e6477ed261 KEYCLOAK-4856
[RHSSO] Adapter feature pack requires org.jboss.eap:wildfly-feature-pack in product
2017-05-05 12:08:22 +02:00
Stian Thorgersen 43f64e51c6 KEYCLOAK-4857
[RHSSO] async-http-servlet-3.0 missing in newest resteasy
2017-05-05 12:08:22 +02:00
Stian Thorgersen b00651391b KEYCLOAK-4859 [RHSSO] Upgrade to EAP 7.1.0 Alpha17 2017-05-05 12:08:22 +02:00
Stan Silvert 2e66cd1070 Merge pull request #4108 from ssilvert/error_description
KEYCLOAK-4462: Unexpected error when creat client w/ existing ClientID
2017-05-04 16:29:43 -04:00
Stan Silvert 55f3d8c1d0 KEYCLOAK-4462: Use errorInterceptor instead of handling errors locally 2017-05-04 15:21:05 -04:00
Marc Heide d5c643eaf9 KEYCLOAK-4521: consider offline sessions if no active user session was found for user info endpoint 2017-05-04 15:25:09 +02:00
Stian Thorgersen ee327b7eec Merge pull request #4111 from mstruk/KEYCLOAK-4854
KEYCLOAK-4854 Cordova example fails on iOS 10
2017-05-04 10:43:49 +02:00
Stian Thorgersen 5fd704af58 Merge pull request #4110 from mstruk/KEYCLOAK-4037
KEYCLOAK-4037 JS Adapter fails in Cordova mode for iOS apps
2017-05-04 10:43:14 +02:00
Marko Strukelj aa1eb334e0 KEYCLOAK-4854 Cordova example fails on iOS 10 2017-05-03 17:20:01 +02:00
Marko Strukelj 47ea1ade8a KEYCLOAK-4037 JS Adapter fails in Cordova mode for iOS apps 2017-05-03 17:05:54 +02:00
mhajas b33f7414da KEYCLOAK-4503 Add test 2017-05-03 08:51:26 +02:00
Stian Thorgersen 16aaa3bf01 Merge pull request #4103 from vramik/KEYCLOAK-4819
KEYCLOAK-4819 update product.filename.version
2017-05-02 09:32:50 +02:00
Stan Silvert b8fecca0ba KEYCLOAK-4462: Unexpected error when creating client with existing
ClientID
2017-05-01 18:13:27 -04:00
Stan Silvert b824c4195a Merge pull request #4107 from ssilvert/idp-table-header
KEYCLOAK-4720: Wrongly positioned IdPs table header
2017-05-01 17:10:54 -04:00
Stan Silvert 1438982104 KEYCLOAK-4720: Wrongly positioned IdPs table header 2017-05-01 15:19:44 -04:00
Bill Burke c3b44e61d4 Merge remote-tracking branch 'upstream/master' 2017-05-01 14:51:07 -04:00
Bill Burke 93ef2ec9bf Merge pull request #4105 from patriot1burke/master
KEYCLOAK-4821
2017-04-29 18:01:43 -04:00
Bill Burke af792b8abe fix 2017-04-29 17:03:36 -04:00
Bill Burke 1f4311a02c KEYCLOAK-4821 2017-04-29 10:41:32 -04:00
Bas van Schaik ff6dbd6bde Fix lgtm.com alert: cast int to long before multiplication
The integer multiplication has the potential to overflow before the
result is being cast to the 'long' result.

Details:
https://lgtm.com/projects/g/keycloak/keycloak/snapshot/dist-7900299-1490802114895/files/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java#V133
2017-04-28 14:54:47 +01:00
Bas van Schaik 2df1175315 Fix lgtm.com alert: potential NPE due to non-short circuit logic
The logical-AND operator '&&' evaluates its operands in order, which is
what is required here. The bitwise-AND operator '&' always evaluates all
operands, which will in some cases result in a NPE in the second
operand.

Details:
https://lgtm.com/projects/g/keycloak/keycloak/snapshot/dist-7900299-1490802114895/files/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java#V543
2017-04-28 14:51:51 +01:00
Bas van Schaik eb93eef874 Fix lgtm.com alert: variable 'config' is always null (likely false logic)
Details:
https://lgtm.com/projects/g/keycloak/keycloak/snapshot/dist-7900299-1490802114895/files/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserCredentialStore.java#V122
2017-04-28 14:50:30 +01:00
vramik 5b926a3da6 KEYCLOAK-4819 update product.filename.version 2017-04-28 14:40:37 +02:00
mhajas 618a8e7f90 KEYCLOAK-4650 Add cancel warning test 2017-04-28 14:18:01 +02:00
Alexander Schwartz 5a8634e359 KEYCLOAK-4814 disable keycloak spring boot by configuration 2017-04-28 09:48:42 +02:00
Stian Thorgersen bbed1ffca7 Merge pull request #4097 from stianst/KEYCLOAK-4717
KEYCLOAK-4717 Add test
2017-04-28 09:42:21 +02:00
Stian Thorgersen 09ecc37ccb Merge pull request #3779 from Pirayya/KEYCLOAK-4204-brute-force-extension-for-permanent-lockout
KEYCLOAK-4204 Extend brute force protection with permanent lockout on…
2017-04-28 09:35:55 +02:00
Stian Thorgersen ab8658333f KEYCLOAK-4717 Add test 2017-04-28 09:05:10 +02:00
Eriksson Fabian ca1152c3e5 KEYCLOAK-4204 Extend brute force protection with permanent lockout on failed attempts
- Can still use temporary brute force protection.
- After X-1 failed login attempt, if the user successfully logs in his/her fail login count is reset.
2017-04-28 09:02:10 +02:00
Pavel Drozd 7bcbc9a6af Merge pull request #4042 from daklassen/KEYCLOAK-2976
KEYCLOAK-2976 Merge two "ClientTest" classes in integration-arquillian
2017-04-27 17:16:58 +02:00
Stian Thorgersen 6073f4c159 Merge pull request #4093 from sebastienblanc/update_starter
rename the starter and spring-boot-starter
2017-04-27 16:25:51 +02:00
sebastienblanc dee4548798 rename the starter and spring-boot-starter 2017-04-27 15:54:44 +02:00
Stian Thorgersen 8f9b6a5e44 Merge pull request #4092 from stianst/master
Set version to 3.2.0.CR1-SNAPSHOT
2017-04-27 14:59:29 +02:00
Stian Thorgersen 87dedb56e5 Set version to 3.2.0.CR1-SNAPSHOT 2017-04-27 14:23:03 +02:00
Bill Burke c7bdb489ee Merge remote-tracking branch 'upstream/master' 2017-04-26 18:57:56 -04:00
Bill Burke 2276f99d54 Merge remote-tracking branch 'upstream/master' 2017-04-26 14:39:45 -04:00
Bill Burke f67013bcb6 fix 2017-04-26 14:39:41 -04:00
John Ament b37ed7145c KEYCLOAK-4765 - Adding support for wildfly subsystem disable query parameter parsing. 2017-04-26 09:42:00 -04:00
John Ament 1f98dc5527 KEYCLOAK-4765 - Simplified unit tests. 2017-04-25 20:38:07 -04:00
John Ament 754b0fd123 KEYCLOAK-4765 - Adding integration tests for adapter module. 2017-04-25 20:29:35 -04:00
emilienbondu 46bc102799 adding cors-exposed-headers to conf
add missing field in the BaseAdapterConfig

cleaning for PR & adding unit test

Adding property to subsystem, removing formatting changes
2017-04-25 12:02:17 +02:00
John Ament cb7cef8858 KEYCLOAK-4765 - Add ability to disable Query Parameter parsing. 2017-04-24 14:42:03 -04:00
Bill Burke 12cb295a35 Merge remote-tracking branch 'upstream/master' 2017-04-24 10:05:46 -04:00
Bill Burke 58868ca99f prototype 2017-04-24 10:05:39 -04:00
Frederik Libert b84f6d306d KEYCLOAK-4781 Support for an AttributeStatement Mapper 2017-04-24 11:29:55 +02:00
David Klassen 19a59429ae KEYCLOAK-2976 Merge two "ClientTest" classes in integration-arquillian 2017-04-19 13:25:30 +02:00
Anders Båtstrand 89c6cda2ac Two new configuration options for the Saml broker:
* wantAssertionsSigned: This will toggle the flag in the SP Metadata Descriptor, and validate the signature if and only if "Validate signature" is selected.
 * wantAssertionsEncrypted: This will simply require that the assertion is encrypted.

 Default behavior is unchanged. The signature validation uses the original XML, and supports therefore an IdP that adds whitespace and line breaks between tags (for example OpenAM).
2017-02-24 15:08:57 +01:00
1944 changed files with 151418 additions and 33855 deletions

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ before_script:
- export MAVEN_SKIP_RC=true
install:
- travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTests=true -B -V -q
- travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTestsuite -B -V -q
script:
- ./travis-run-tests.sh $TESTS
+3 -3
View File
@@ -41,10 +41,10 @@ To start Keycloak during development first build as specified above, then run:
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
To start Keycloak from the appliance distribution first build the distribution it as specified above, then run:
To start Keycloak from the server distribution first build the distribution it as specified above, then run:
tar xfz distribution/appliance-dist/target/keycloak-appliance-dist-all-<VERSION>.tar.gz
cd keycloak-appliance-dist-all-<VERSION>/keycloak
tar xfz distribution/server-dist/target/keycloak-<VERSION>.tar.gz
cd keycloak-<VERSION>
bin/standalone.sh
To stop the server press `Ctrl + C`.
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -101,6 +101,7 @@ public class AuthenticatedActionsHandler {
if (!deployment.isCors()) return false;
KeycloakSecurityContext securityContext = facade.getSecurityContext();
String origin = facade.getRequest().getHeader(CorsHeaders.ORIGIN);
String exposeHeaders = deployment.getCorsExposedHeaders();
String requestOrigin = UriUtils.getOrigin(facade.getRequest().getURI());
log.debugv("Origin: {0} uri: {1}", origin, facade.getRequest().getURI());
if (securityContext != null && origin != null && !origin.equals(requestOrigin)) {
@@ -124,6 +125,9 @@ public class AuthenticatedActionsHandler {
facade.getResponse().setStatus(200);
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
if (exposeHeaders != null) {
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, exposeHeaders);
}
} else {
log.debugv("cors validation not needed as we're not a secure session or origin header was null: {0}", facade.getRequest().getURI());
}
@@ -30,4 +30,5 @@ public interface CorsHeaders {
String ORIGIN = "Origin";
String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
}
@@ -170,8 +170,8 @@ public class HttpClientBuilder {
return this;
}
public HttpClientBuilder disableCookieCache() {
this.disableCookieCache = true;
public HttpClientBuilder disableCookieCache(boolean disable) {
this.disableCookieCache = disable;
return this;
}
@@ -334,7 +334,7 @@ public class HttpClientBuilder {
}
public HttpClient build(AdapterHttpClientConfig adapterConfig) {
disableCookieCache(); // disable cookie cache as we don't want sticky sessions for load balancing
disableCookieCache(true); // disable cookie cache as we don't want sticky sessions for load balancing
String truststorePath = adapterConfig.getTruststore();
if (truststorePath != null) {
@@ -35,6 +35,8 @@ import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @author <a href="mailto:brad.culley@spartasystems.com">Brad Culley</a>
* @author <a href="mailto:john.ament@spartasystems.com">John D. Ament</a>
* @version $Revision: 1 $
*/
public class KeycloakDeployment {
@@ -73,6 +75,7 @@ public class KeycloakDeployment {
protected int corsMaxAge = -1;
protected String corsAllowedHeaders;
protected String corsAllowedMethods;
protected String corsExposedHeaders;
protected boolean exposeToken;
protected boolean alwaysRefreshToken;
protected boolean registerNodeAtStartup;
@@ -87,6 +90,9 @@ public class KeycloakDeployment {
// https://tools.ietf.org/html/rfc7636
protected boolean pkce = false;
protected boolean ignoreOAuthQueryParameter;
protected Map<String, String> redirectRewriteRules;
public KeycloakDeployment() {
}
@@ -325,6 +331,14 @@ public class KeycloakDeployment {
this.corsAllowedMethods = corsAllowedMethods;
}
public String getCorsExposedHeaders() {
return corsExposedHeaders;
}
public void setCorsExposedHeaders(String corsExposedHeaders) {
this.corsExposedHeaders = corsExposedHeaders;
}
public boolean isExposeToken() {
return exposeToken;
}
@@ -427,4 +441,21 @@ public class KeycloakDeployment {
this.pkce = pkce;
}
public void setIgnoreOAuthQueryParameter(boolean ignoreOAuthQueryParameter) {
this.ignoreOAuthQueryParameter = ignoreOAuthQueryParameter;
}
public boolean isOAuthQueryParameterEnabled() {
return !this.ignoreOAuthQueryParameter;
}
public Map<String, String> getRedirectRewriteRules() {
return redirectRewriteRules;
}
public void setRewriteRedirectRules(Map<String, String> redirectRewriteRules) {
this.redirectRewriteRules = redirectRewriteRules;
}
}
@@ -37,6 +37,8 @@ import java.security.PublicKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @author <a href="mailto:brad.culley@spartasystems.com">Brad Culley</a>
* @author <a href="mailto:john.ament@spartasystems.com">John D. Ament</a>
* @version $Revision: 1 $
*/
public class KeycloakDeploymentBuilder {
@@ -96,6 +98,7 @@ public class KeycloakDeploymentBuilder {
deployment.setCorsMaxAge(adapterConfig.getCorsMaxAge());
deployment.setCorsAllowedHeaders(adapterConfig.getCorsAllowedHeaders());
deployment.setCorsAllowedMethods(adapterConfig.getCorsAllowedMethods());
deployment.setCorsExposedHeaders(adapterConfig.getCorsExposedHeaders());
}
// https://tools.ietf.org/html/rfc7636
@@ -112,6 +115,8 @@ public class KeycloakDeploymentBuilder {
deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
deployment.setMinTimeBetweenJwksRequests(adapterConfig.getMinTimeBetweenJwksRequests());
deployment.setPublicKeyCacheTtl(adapterConfig.getPublicKeyCacheTtl());
deployment.setIgnoreOAuthQueryParameter(adapterConfig.isIgnoreOAuthQueryParameter());
deployment.setRewriteRedirectRules(adapterConfig.getRedirectRewriteRules());
if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
@@ -25,7 +25,6 @@ import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.common.VerificationException;
import org.keycloak.common.util.Encode;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.UriUtils;
import org.keycloak.constants.AdapterConstants;
@@ -38,7 +37,10 @@ import org.keycloak.representations.IDToken;
import org.keycloak.util.TokenUtil;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.logging.Level;
/**
@@ -141,6 +143,7 @@ public class OAuthRequestAuthenticator {
protected String getRedirectUri(String state) {
String url = getRequestUrl();
log.debugf("callback uri: %s", url);
if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
int port = sslRedirectPort();
if (port < 0) {
@@ -170,7 +173,7 @@ public class OAuthRequestAuthenticator {
KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, Encode.encodeQueryParamAsIs(url)) // Need to encode uri ourselves as queryParam() will not encode % characters.
.queryParam(OAuth2Constants.REDIRECT_URI, rewrittenRedirectUri(url))
.queryParam(OAuth2Constants.STATE, state)
.queryParam("login", "true");
if(loginHint != null && loginHint.length() > 0){
@@ -320,10 +323,11 @@ public class OAuthRequestAuthenticator {
AccessTokenResponse tokenResponse = null;
strippedOauthParametersRequestUri = stripOauthParametersFromRedirect();
try {
// For COOKIE store we don't have httpSessionId and single sign-out won't be available
String httpSessionId = deployment.getTokenStore() == TokenStore.SESSION ? reqAuthenticator.changeHttpSessionId(true) : null;
tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri, httpSessionId);
tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, rewrittenRedirectUri(strippedOauthParametersRequestUri), httpSessionId);
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to turn code into token");
log.error("status from server: " + failure.getStatus());
@@ -375,6 +379,23 @@ public class OAuthRequestAuthenticator {
.replaceQueryParam(OAuth2Constants.STATE, null);
return builder.build().toString();
}
private String rewrittenRedirectUri(String originalUri) {
Map<String, String> rewriteRules = deployment.getRedirectRewriteRules();
if(rewriteRules != null && !rewriteRules.isEmpty()) {
try {
URL url = new URL(originalUri);
Map.Entry<String, String> rule = rewriteRules.entrySet().iterator().next();
StringBuilder redirectUriBuilder = new StringBuilder(url.getProtocol());
redirectUriBuilder.append("://"+ url.getAuthority());
redirectUriBuilder.append(url.getPath().replaceFirst(rule.getKey(), rule.getValue()));
return redirectUriBuilder.toString();
} catch (MalformedURLException ex) {
log.error("Not a valid request url");
throw new RuntimeException(ex);
}
}
return originalUri;
}
}
@@ -22,6 +22,8 @@ import org.keycloak.adapters.spi.HttpFacade;
/**
* @author <a href="mailto:froehlich.ch@gmail.com">Christian Froehlich</a>
* @author <a href="mailto:brad.culley@spartasystems.com">Brad Culley</a>
* @author <a href="mailto:john.ament@spartasystems.com">John D. Ament</a>
* @version $Revision: 1 $
*/
public class QueryParamterTokenRequestAuthenticator extends BearerTokenRequestAuthenticator {
@@ -33,6 +35,9 @@ public class QueryParamterTokenRequestAuthenticator extends BearerTokenRequestAu
}
public AuthOutcome authenticate(HttpFacade exchange) {
if(!deployment.isOAuthQueryParameterEnabled()) {
return AuthOutcome.NOT_ATTEMPTED;
}
tokenString = null;
tokenString = getAccessTokenFromQueryParamter(exchange);
if (tokenString == null || tokenString.trim().isEmpty()) {
@@ -78,13 +78,13 @@ public abstract class AbstractPolicyEnforcer {
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken);
return createAuthorizationContext(accessToken, null);
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
return createAuthorizationContext(accessToken);
return createAuthorizationContext(accessToken, null);
}
handleAccessDenied(httpFacade);
@@ -100,7 +100,7 @@ public abstract class AbstractPolicyEnforcer {
if (isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken);
return createAuthorizationContext(accessToken, pathConfig);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
}
@@ -252,8 +252,8 @@ public abstract class AbstractPolicyEnforcer {
return requiredScopes;
}
private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
return new ClientAuthorizationContext(accessToken, this.paths, authzClient);
private AuthorizationContext createAuthorizationContext(AccessToken accessToken, PathConfig pathConfig) {
return new ClientAuthorizationContext(accessToken, pathConfig, this.paths, authzClient);
}
private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
@@ -17,6 +17,8 @@
*/
package org.keycloak.adapters.authorization;
import java.util.Set;
import org.jboss.logging.Logger;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade;
@@ -26,8 +28,6 @@ import org.keycloak.authorization.client.resource.PermissionResource;
import org.keycloak.authorization.client.resource.ProtectionResource;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
@@ -52,7 +52,7 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
private void challengeEntitlementAuthentication(OIDCHttpFacade facade) {
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String clientId = authzClient.getConfiguration().getClientId();
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 + "\"");
@@ -65,7 +65,7 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String ticket = getPermissionTicket(pathConfig, requiredScopes, authzClient);
String clientId = authzClient.getConfiguration().getClientId();
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 + "\"");
@@ -127,7 +127,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
AccessToken token = httpFacade.getSecurityContext().getToken();
if (token.getAuthorization() == null) {
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getResource());
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
} else {
EntitlementRequest request = new EntitlementRequest();
@@ -137,7 +137,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
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().getClientId(), request);
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getResource(), request);
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
}
}
@@ -29,10 +29,13 @@ import org.keycloak.common.util.PemUtils;
import org.keycloak.enums.TokenStore;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
* @author <a href="mailto:brad.culley@spartasystems.com">Brad Culley</a>
* @author <a href="mailto:john.ament@spartasystems.com">John D. Ament</a>
*/
public class KeycloakDeploymentBuilderTest {
@@ -53,10 +56,12 @@ public class KeycloakDeploymentBuilderTest {
assertEquals(1000, deployment.getCorsMaxAge());
assertEquals("POST, PUT, DELETE, GET", deployment.getCorsAllowedMethods());
assertEquals("X-Custom, X-Custom2", deployment.getCorsAllowedHeaders());
assertEquals("X-Custom3, X-Custom4", deployment.getCorsExposedHeaders());
assertTrue(deployment.isBearerOnly());
assertTrue(deployment.isPublicClient());
assertTrue(deployment.isEnableBasicAuth());
assertTrue(deployment.isExposeToken());
assertFalse(deployment.isOAuthQueryParameterEnabled());
assertEquals("234234-234234-234234", deployment.getResourceCredentials().get("secret"));
assertEquals(ClientIdAndSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
assertEquals(20, ((ThreadSafeClientConnManager) deployment.getClient().getConnectionManager()).getMaxTotal());
@@ -70,6 +75,7 @@ public class KeycloakDeploymentBuilderTest {
assertEquals(10, deployment.getTokenMinimumTimeToLive());
assertEquals(20, deployment.getMinTimeBetweenJwksRequests());
assertEquals(120, deployment.getPublicKeyCacheTtl());
assertEquals("/api/$1", deployment.getRedirectRewriteRules().get("^/wsmaster/api/(.*)$"));
}
@Test
@@ -0,0 +1,49 @@
/*
* 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;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:brad.culley@spartasystems.com">Brad Culley</a>
* @author <a href="mailto:john.ament@spartasystems.com">John D. Ament</a>
*/
public class KeycloakDeploymentTest {
@Test
public void shouldNotEnableOAuthQueryParamWhenIgnoreIsTrue() {
KeycloakDeployment keycloakDeployment = new KeycloakDeployment();
keycloakDeployment.setIgnoreOAuthQueryParameter(true);
assertFalse(keycloakDeployment.isOAuthQueryParameterEnabled());
}
@Test
public void shouldEnableOAuthQueryParamWhenIgnoreIsFalse() {
KeycloakDeployment keycloakDeployment = new KeycloakDeployment();
keycloakDeployment.setIgnoreOAuthQueryParameter(false);
assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled());
}
@Test
public void shouldEnableOAuthQueryParamWhenIgnoreNotSet() {
KeycloakDeployment keycloakDeployment = new KeycloakDeployment();
assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled());
}
}
@@ -9,6 +9,7 @@
"cors-max-age": 1000,
"cors-allowed-methods": "POST, PUT, DELETE, GET",
"cors-allowed-headers": "X-Custom, X-Custom2",
"cors-exposed-headers": "X-Custom3, X-Custom4",
"bearer-only": true,
"public-client": true,
"enable-basic-auth": true,
@@ -31,5 +32,9 @@
"principal-attribute": "email",
"token-minimum-time-to-live": 10,
"min-time-between-jwks-requests": 20,
"public-key-cache-ttl": 120
"public-key-cache-ttl": 120,
"ignore-oauth-query-parameter": true,
"redirect-rewrite-rules" : {
"^/wsmaster/api/(.*)$" : "/api/$1"
}
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+59
View File
@@ -0,0 +1,59 @@
/*
* MIT License
*
* Copyright 2017 Brett Epps <https://github.com/eppsilon>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import * as Keycloak from 'keycloak';
export as namespace KeycloakAuthorization;
export = KeycloakAuthorization;
/**
* Creates a new Keycloak client instance.
* @param config Path to a JSON config file or a plain config object.
*/
declare function KeycloakAuthorization(keycloak: Keycloak.KeycloakInstance): KeycloakAuthorization.KeycloakAuthorizationInstance;
declare namespace KeycloakAuthorization {
interface KeycloakAuthorizationPromise {
then(onGrant: (rpt: string) => void, onDeny: () => void, onError: () => void): void;
}
interface KeycloakAuthorizationInstance {
rpt: any;
config: { rpt_endpoint: string };
init(): void;
/**
* This method enables client applications to better integrate with resource servers protected by a Keycloak
* policy enforcer.
*
* In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
* 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.
*/
authorize(wwwAuthenticateHeader: string): KeycloakAuthorizationPromise;
/**
* Obtains all entitlements from a Keycloak server based on a given resourceServerId.
*/
entitlement(resourceServerId: string, entitlementRequest: {}): KeycloakAuthorizationPromise;
}
}
+464 -87
View File
@@ -1,101 +1,478 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
* MIT License
*
* 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
* Copyright 2017 Brett Epps <https://github.com/eppsilon>
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* 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.
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
declare module KeycloakModule {
export as namespace Keycloak;
export interface Promise {
success(callback: Function): Promise;
error(callback: Function): Promise;
}
export = Keycloak;
export type ResponseModes = "query" | "fragment";
export type Flows = "standard" | "implicit" | "hybrid";
export interface InitOptions {
checkLoginIframe?: boolean;
checkLoginIframeInterval?: number;
onLoad?: string;
adapter?: string;
responseMode?: ResponseModes;
flow?: Flows;
token?: string;
refreshToken?: string;
idToken?: string;
timeSkew?: number;
}
/**
* Creates a new Keycloak client instance.
* @param config Path to a JSON config file or a plain config object.
*/
declare function Keycloak(config?: string|{}): Keycloak.KeycloakInstance;
export interface LoginOptions {
redirectUri?: string;
prompt?: string;
maxAge?: number;
loginHint?: string;
action?: string;
locale?: string;
}
declare namespace Keycloak {
type KeycloakAdapterName = 'cordova'|'default';
type KeycloakOnLoad = 'login-required'|'check-sso';
type KeycloakResponseMode = 'query'|'fragment';
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
type KeycloakFlow = 'standard'|'implicit'|'hybrid';
export interface RedirectUriOptions {
redirectUri?: string;
}
interface KeycloakInitOptions {
/**
* @private Undocumented.
*/
adapter?: KeycloakAdapterName;
export interface KeycloakClient {
init(options?: InitOptions): Promise;
login(options?: LoginOptions): Promise;
createLoginUrl(options?: LoginOptions): string;
logout(options?: RedirectUriOptions): Promise;
createLogoutUrl(options?: RedirectUriOptions): string;
register(options?: LoginOptions): Promise;
createRegisterUrl(options?: RedirectUriOptions): string;
accountManagement(): Promise;
createAccountUrl(options?: RedirectUriOptions): string;
hasRealmRole(role: string): boolean;
hasResourceRole(role: string, resource?: string): boolean;
loadUserProfile(): Promise;
isTokenExpired(minValidity: number): boolean;
updateToken(minValidity: number): Promise;
clearToken(): any;
/**
* Specifies an action to do on load.
*/
onLoad?: KeycloakOnLoad;
realm: string;
clientId: string;
authServerUrl: string;
/**
* Set an initial value for the token.
*/
token?: string;
token: string;
tokenParsed: any;
refreshToken: string;
refreshTokenParsed: any;
idToken: string;
idTokenParsed: any;
realmAccess: any;
resourceAccess: any;
authenticated: boolean;
subject: string;
timeSkew: number;
responseMode: ResponseModes;
flow: Flows;
responseType: string;
/**
* Set an initial value for the refresh token.
*/
refreshToken?: string;
onReady: Function;
onAuthSuccess: Function;
onAuthError: Function;
onAuthRefreshSuccess: Function;
onAuthRefreshError: Function;
onAuthLogout: Function;
onTokenExpired: Function;
}
/**
* Set an initial value for the id token (only together with `token` or
* `refreshToken`).
*/
idToken?: string;
/**
* Set an initial value for skew between local time and Keycloak server in
* seconds (only together with `token` or `refreshToken`).
*/
timeSkew?: number;
/**
* Set to enable/disable monitoring login state.
* @default true
*/
checkLoginIframe?: boolean;
/**
* Set the interval to check login state (in seconds).
* @default 5
*/
checkLoginIframeInterval?: boolean;
/**
* Set the OpenID Connect response mode to send to Keycloak upon login.
* @default fragment After successful authentication Keycloak will redirect
* to JavaScript application with OpenID Connect parameters
* added in URL fragment. This is generally safer and
* recommended over query.
*/
responseMode?: KeycloakResponseMode;
/**
* Set the OpenID Connect flow.
* @default standard
*/
flow?: KeycloakFlow;
}
interface KeycloakLoginOptions {
/**
* @private Undocumented.
*/
scope?: string;
/**
* Specifies the uri to redirect to after login.
*/
redirectUri?: string;
/**
* By default the login screen is displayed if the user is not logged into
* Keycloak. To only authenticate to the application if the user is already
* logged in and not display the login page if the user is not logged in, set
* this option to `'none'`. To always require re-authentication and ignore
* SSO, set this option to `'login'`.
*/
prompt?: 'none'|'login';
/**
* If value is `'register'` then user is redirected to registration page,
* otherwise to login page.
*/
action?: 'register';
/**
* Used just if user is already authenticated. Specifies maximum time since
* the authentication of user happened. If user is already authenticated for
* longer time than `'maxAge'`, the SSO is ignored and he will need to
* authenticate again.
*/
maxAge?: number;
/**
* Used to pre-fill the username/email field on the login form.
*/
loginHint?: string;
/**
* Used to tell Keycloak which IDP the user wants to authenticate with.
*/
idpHint?: string;
/**
* Specifies the desired locale for the UI.
*/
locale?: string;
}
type KeycloakPromiseCallback<T> = (result: T) => void;
interface KeycloakPromise<TSuccess, TError> {
/**
* Function to call if the promised action succeeds.
*/
success(callback: KeycloakPromiseCallback<TSuccess>): KeycloakPromise<TSuccess, TError>;
/**
* Function to call if the promised action throws an error.
*/
error(callback: KeycloakPromiseCallback<TError>): KeycloakPromise<TSuccess, TError>;
}
interface KeycloakError {
error: string;
error_description: string;
}
interface KeycloakAdapter {
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
logout(options?: any): KeycloakPromise<void, void>;
register(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
accountManagement(): KeycloakPromise<void, void>;
redirectUri(options: { redirectUri: string; }, encodeHash: boolean): string;
}
interface KeycloakProfile {
id?: string;
username?: string;
email?: string;
firstName?: string;
lastName?: string;
enabled?: boolean;
emailVerified?: boolean;
totp?: boolean;
createdTimestamp?: number;
}
// export interface KeycloakUserInfo {}
/**
* A client for the Keycloak authentication server.
* @see {@link https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/javascript-adapter.html|Keycloak JS adapter documentation}
*/
interface KeycloakInstance {
/**
* Is true if the user is authenticated, false otherwise.
*/
authenticated?: boolean;
/**
* The user id.
*/
subject?: string;
/**
* Response mode passed in init (default value is `'fragment'`).
*/
responseMode?: KeycloakResponseMode;
/**
* Response type sent to Keycloak with login requests. This is determined
* based on the flow value used during initialization, but can be overridden
* by setting this value.
*/
responseType?: KeycloakResponseType;
/**
* Flow passed in init.
*/
flow?: KeycloakFlow;
/**
* The realm roles associated with the token.
*/
realmAccess?: { roles: string[] };
/**
* The resource roles associated with the token.
*/
resourceAccess?: string[];
/**
* The base64 encoded token that can be sent in the Authorization header in
* requests to services.
*/
token?: string;
/**
* The parsed token as a JavaScript object.
*/
tokenParsed?: {
exp?: number;
iat?: number;
nonce?: string;
sub?: string;
session_state?: string;
realm_access?: { roles: string[] };
resource_access?: string[];
};
/**
* The base64 encoded refresh token that can be used to retrieve a new token.
*/
refreshToken?: string;
/**
* The parsed refresh token as a JavaScript object.
*/
refreshTokenParsed?: { nonce?: string };
/**
* The base64 encoded ID token.
*/
idToken?: string;
/**
* The parsed id token as a JavaScript object.
*/
idTokenParsed?: { nonce?: string };
/**
* The estimated time difference between the browser time and the Keycloak
* server in seconds. This value is just an estimation, but is accurate
* enough when determining if a token is expired or not.
*/
timeSkew?: number;
/**
* @private Undocumented.
*/
loginRequired?: boolean;
/**
* @private Undocumented.
*/
authServerUrl?: string;
/**
* @private Undocumented.
*/
realm?: string;
/**
* @private Undocumented.
*/
clientId?: string;
/**
* @private Undocumented.
*/
clientSecret?: string;
/**
* @private Undocumented.
*/
redirectUri?: string;
/**
* @private Undocumented.
*/
sessionId?: string;
/**
* @private Undocumented.
*/
profile?: KeycloakProfile;
/**
* @private Undocumented.
*/
userInfo?: {}; // KeycloakUserInfo;
/**
* Called when the adapter is initialized.
*/
onReady?(authenticated?: boolean): void;
/**
* Called when a user is successfully authenticated.
*/
onAuthSuccess?(): void;
/**
* Called if there was an error during authentication.
*/
onAuthError?(errorData: KeycloakError): void;
/**
* Called when the token is refreshed.
*/
onAuthRefreshSuccess?(): void;
/**
* Called if there was an error while trying to refresh the token.
*/
onAuthRefreshError?(): void;
/**
* Called if the user is logged out (will only be called if the session
* status iframe is enabled, or in Cordova mode).
*/
onAuthLogout?(): void;
/**
* Called when the access token is expired. If a refresh token is available
* the token can be refreshed with Keycloak#updateToken, or in cases where
* it's not (ie. with implicit flow) you can redirect to login screen to
* obtain a new access token.
*/
onTokenExpired?(): void;
/**
* Called to initialize the adapter.
* @param initOptions Initialization options.
* @returns A promise to set functions to be invoked on success or error.
*/
init(initOptions: KeycloakInitOptions): KeycloakPromise<boolean, KeycloakError>;
/**
* Redirects to login form.
* @param options Login options.
*/
login(options?: KeycloakLoginOptions): KeycloakPromise<void, void>;
/**
* Redirects to logout.
* @param options Logout options.
* @param options.redirectUri Specifies the uri to redirect to after logout.
*/
logout(options?: any): KeycloakPromise<void, void>;
/**
* Redirects to registration form.
* @param options Supports same options as Keycloak#login but `action` is
* set to `'register'`.
*/
register(options?: any): KeycloakPromise<void, void>;
/**
* Redirects to the Account Management Console.
*/
accountManagement(): KeycloakPromise<void, void>;
/**
* Returns the URL to login form.
* @param options Supports same options as Keycloak#login.
*/
createLoginUrl(options?: KeycloakLoginOptions): string;
/**
* Returns the URL to logout the user.
* @param options Logout options.
* @param options.redirectUri Specifies the uri to redirect to after logout.
*/
createLogoutUrl(options?: any): string;
/**
* Returns the URL to registration page.
* @param options Supports same options as Keycloak#createLoginUrl but
* `action` is set to `'register'`.
*/
createRegisterUrl(options?: KeycloakLoginOptions): string;
/**
* Returns the URL to the Account Management Console.
*/
createAccountUrl(): string;
/**
* Returns true if the token has less than `minValidity` seconds left before
* it expires.
* @param minValidity If not specified, `0` is used.
*/
isTokenExpired(minValidity?: number): boolean;
/**
* If the token expires within `minValidity` seconds, the token is refreshed.
* If the session status iframe is enabled, the session status is also
* checked.
* @returns A promise to set functions that can be invoked if the token is
* still valid, or if the token is no longer valid.
* @example
* ```js
* keycloak.updateToken(5).success(function(refreshed) {
* if (refreshed) {
* alert('Token was successfully refreshed');
* } else {
* alert('Token is still valid');
* }
* }).error(function() {
* alert('Failed to refresh the token, or the session has expired');
* });
*/
updateToken(minValidity: number): KeycloakPromise<boolean, boolean>;
/**
* Clears authentication state, including tokens. This can be useful if
* the application has detected the session was expired, for example if
* updating token fails. Invoking this results in Keycloak#onAuthLogout
* callback listener being invoked.
*/
clearToken(): void;
/**
* Returns true if the token has the given realm role.
* @param role A realm role name.
*/
hasRealmRole(role: string): boolean;
/**
* Returns true if the token has the given role for the resource.
* @param role A role name.
* @param resource If not specified, `clientId` is used.
*/
hasResourceRole(role: string, resource?: string): boolean;
/**
* Loads the user's profile.
* @returns A promise to set functions to be invoked on success or error.
*/
loadUserProfile(): KeycloakPromise<KeycloakProfile, void>;
/**
* @private Undocumented.
*/
loadUserInfo(): KeycloakPromise<{}, void>;
}
}
declare var Keycloak: {
new(config?: any): KeycloakModule.KeycloakClient;
};
@@ -587,7 +587,7 @@
req.onreadystatechange = function () {
if (req.readyState == 4) {
if (req.status == 200) {
if (req.status == 200 || fileLoaded(req)) {
var config = JSON.parse(req.responseText);
kc.authServerUrl = config['auth-server-url'];
@@ -633,6 +633,10 @@
return promise.promise;
}
function fileLoaded(xhr) {
return xhr.status == 0 && xhr.responseText && xhr.responseURL.startsWith('file:');
}
function setToken(token, refreshToken, idToken, timeLocal) {
if (kc.tokenTimeoutHandle) {
clearTimeout(kc.tokenTimeoutHandle);
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -54,72 +54,96 @@ import java.util.regex.Pattern;
*/
public class KeycloakOIDCFilter implements Filter {
private final static Logger log = Logger.getLogger("" + KeycloakOIDCFilter.class);
public static final String SKIP_PATTERN_PARAM = "keycloak.config.skipPattern";
public static final String CONFIG_RESOLVER_PARAM = "keycloak.config.resolver";
public static final String CONFIG_FILE_PARAM = "keycloak.config.file";
public static final String CONFIG_PATH_PARAM = "keycloak.config.path";
protected AdapterDeploymentContext deploymentContext;
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
protected NodesRegistrationManagement nodesRegistrationManagement;
protected Pattern skipPattern;
private final static Logger log = Logger.getLogger(""+KeycloakOIDCFilter.class);
private final KeycloakConfigResolver definedconfigResolver;
/**
* Constructor that can be used to define a {@code KeycloakConfigResolver} that will be used at initialization to
* provide the {@code KeycloakDeployment}.
* @param definedconfigResolver the resolver
*/
public KeycloakOIDCFilter(KeycloakConfigResolver definedconfigResolver) {
this.definedconfigResolver = definedconfigResolver;
}
public KeycloakOIDCFilter() {
this(null);
}
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
String skipPatternDefinition = filterConfig.getInitParameter(SKIP_PATTERN_PARAM);
if (skipPatternDefinition != null) {
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
}
String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
if (configResolverClass != null) {
try {
KeycloakConfigResolver configResolver = (KeycloakConfigResolver) getClass().getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
} catch (Exception ex) {
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
if (definedconfigResolver != null) {
deploymentContext = new AdapterDeploymentContext(definedconfigResolver);
log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", definedconfigResolver.getClass());
} else {
String fp = filterConfig.getInitParameter("keycloak.config.file");
InputStream is = null;
if (fp != null) {
String configResolverClass = filterConfig.getInitParameter(CONFIG_RESOLVER_PARAM);
if (configResolverClass != null) {
try {
is = new FileInputStream(fp);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
KeycloakConfigResolver configResolver = (KeycloakConfigResolver) getClass().getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
log.log(Level.INFO, "Using {0} to resolve Keycloak configuration on a per-request basis.", configResolverClass);
} catch (Exception ex) {
log.log(Level.FINE, "The specified resolver {0} could NOT be loaded. Keycloak is unconfigured and will deny all requests. Reason: {1}", new Object[]{configResolverClass, ex.getMessage()});
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
} else {
String path = "/WEB-INF/keycloak.json";
String pathParam = filterConfig.getInitParameter("keycloak.config.path");
if (pathParam != null) path = pathParam;
is = filterConfig.getServletContext().getResourceAsStream(path);
String fp = filterConfig.getInitParameter(CONFIG_FILE_PARAM);
InputStream is = null;
if (fp != null) {
try {
is = new FileInputStream(fp);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
} else {
String path = "/WEB-INF/keycloak.json";
String pathParam = filterConfig.getInitParameter(CONFIG_PATH_PARAM);
if (pathParam != null) path = pathParam;
is = filterConfig.getServletContext().getResourceAsStream(path);
}
KeycloakDeployment kd = createKeycloakDeploymentFrom(is);
deploymentContext = new AdapterDeploymentContext(kd);
log.fine("Keycloak is using a per-deployment configuration.");
}
KeycloakDeployment kd = createKeycloakDeploymentFrom(is);
deploymentContext = new AdapterDeploymentContext(kd);
log.fine("Keycloak is using a per-deployment configuration.");
}
filterConfig.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
nodesRegistrationManagement = new NodesRegistrationManagement();
}
private KeycloakDeployment createKeycloakDeploymentFrom(InputStream is) {
if (is == null) {
log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
return new KeycloakDeployment();
}
return KeycloakDeploymentBuilder.build(is);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
log.fine("Keycloak OIDC Filter");
//System.err.println("Keycloak OIDC Filter: " + ((HttpServletRequest)req).getRequestURL().toString());
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
@@ -201,7 +225,7 @@ public class KeycloakOIDCFilter implements Filter {
*
* @param request the request to check
* @return {@code true} if the request should not be handled,
* {@code false} otherwise.
* {@code false} otherwise.
*/
private boolean shouldSkip(HttpServletRequest request) {
@@ -168,7 +168,7 @@ public class OIDCFilterSessionStore extends FilterSessionStore implements Adapte
HttpSession httpSession = request.getSession();
httpSession.setAttribute(KeycloakAccount.class.getName(), sAccount);
httpSession.setAttribute(KeycloakSecurityContext.class.getName(), sAccount.getKeycloakSecurityContext());
if (idMapper != null) idMapper.map(account.getKeycloakSecurityContext().getToken().getClientSession(), account.getPrincipal().getName(), httpSession.getId());
if (idMapper != null) idMapper.map(account.getKeycloakSecurityContext().getToken().getSessionState(), account.getPrincipal().getName(), httpSession.getId());
//String username = securityContext.getToken().getSubject();
//log.fine("userSessionManagement.login: " + username);
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
@@ -52,6 +52,7 @@
<include>org.keycloak:keycloak-jetty-adapter-spi</include>
</includes>
</artifactSet>
<createSourcesJar>true</createSourcesJar>
</configuration>
</execution>
</executions>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,6 +33,7 @@ import org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve;
import org.keycloak.adapters.undertow.KeycloakServletExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
@@ -60,6 +61,7 @@ import java.util.Set;
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(KeycloakSpringBootProperties.class)
@ConditionalOnProperty(value = "keycloak.enabled", matchIfMissing = true)
public class KeycloakAutoConfiguration {
private KeycloakSpringBootProperties keycloakProperties;
@@ -34,6 +34,11 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
@JsonIgnore
private Map config = new HashMap();
/**
* Allow enabling of Keycloak Spring Boot adapter by configuration.
*/
private boolean enabled = true;
public Map getConfig() {
return config;
}
@@ -43,6 +48,14 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
*/
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* This matches security-constraint of the servlet spec
*/
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,25 @@
package org.keycloak.adapters.springsecurity;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Add this annotation to a class that extends {@code KeycloakWebSecurityConfigurerAdapter} to provide
* a keycloak based Spring security configuration.
*
* @author Hendrik Ebbers
*/
@Retention(value = RUNTIME)
@Target(value = { TYPE })
@Configuration
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
@EnableWebSecurity
public @interface KeycloakConfiguration {
}
@@ -0,0 +1,41 @@
/*
* 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.springsecurity.authentication;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
/**
* To return the forbidden code with the corresponding message.
*
* @author emilienbondu
*
*/
public class KeycloakAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unable to authenticate using the Authorization header");
}
}
@@ -17,6 +17,13 @@
package org.keycloak.adapters.springsecurity.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
@@ -25,7 +32,7 @@ import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationFailureHandler;
import org.keycloak.adapters.springsecurity.authentication.SpringSecurityRequestAuthenticator;
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
import org.keycloak.adapters.springsecurity.token.AdapterTokenStoreFactory;
@@ -41,19 +48,12 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Provides a Keycloak authentication processing filter.
*
@@ -61,11 +61,13 @@ import java.io.IOException;
* @version $Revision: 1 $
*/
public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
public static final String DEFAULT_LOGIN_URL = "/sso/login";
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String SCHEME_BEARER = "bearer ";
public static final String SCHEME_BASIC = "basic ";
/**
* Request matcher that matches requests to the {@link KeycloakAuthenticationEntryPoint#DEFAULT_LOGIN_URI default login URI}
* and any request with a <code>Authorization</code> header.
@@ -89,7 +91,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
*/
public KeycloakAuthenticationProcessingFilter(AuthenticationManager authenticationManager) {
this(authenticationManager, DEFAULT_REQUEST_MATCHER);
setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(DEFAULT_LOGIN_URL));
setAuthenticationFailureHandler(new KeycloakAuthenticationFailureHandler());
}
/**
@@ -109,7 +111,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
*
*/
public KeycloakAuthenticationProcessingFilter(AuthenticationManager authenticationManager, RequestMatcher
requiresAuthenticationRequestMatcher) {
requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.authenticationManager = authenticationManager;
@@ -140,9 +142,27 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
log.debug("Auth outcome: {}", result);
if (AuthOutcome.FAILED.equals(result)) {
throw new KeycloakAuthenticationException("Auth outcome: " + result);
AuthChallenge challenge = authenticator.getChallenge();
if (challenge != null) {
challenge.challenge(facade);
}
throw new KeycloakAuthenticationException("Invalid authorization header, see WWW-Authenticate header for details");
}
if (AuthOutcome.NOT_ATTEMPTED.equals(result)) {
AuthChallenge challenge = authenticator.getChallenge();
if (challenge != null) {
challenge.challenge(facade);
}
if (deployment.isBearerOnly()) {
// no redirection in this mode, throwing exception for the spring handler
throw new KeycloakAuthenticationException("Authorization header not found, see WWW-Authenticate header");
} else {
// let continue if challenged, it may redirect
return null;
}
}
else if (AuthOutcome.AUTHENTICATED.equals(result)) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Assert.notNull(authentication, "Authentication SecurityContextHolder was null");
@@ -184,7 +204,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
Authentication authResult) throws IOException, ServletException {
if (!(this.isBearerTokenRequest(request) || this.isBasicAuthRequest(request))) {
super.successfulAuthentication(request, response, chain, authResult);
@@ -212,19 +232,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
if (this.isBearerTokenRequest(request)) {
SecurityContextHolder.clearContext();
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unable to authenticate bearer token");
return;
}
else if (this.isBasicAuthRequest(request)) {
SecurityContextHolder.clearContext();
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unable to authenticate with basic authentication");
return;
}
AuthenticationException failed) throws IOException, ServletException {
super.unsuccessfulAuthentication(request, response, failed);
}
@@ -262,4 +270,4 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
public final void setContinueChainBeforeSuccessfulAuthentication(boolean continueChainBeforeSuccessfulAuthentication) {
throw new UnsupportedOperationException("This filter does not support explicitly setting a continue chain before success policy");
}
}
}
@@ -27,6 +27,7 @@ import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.springsecurity.KeycloakAuthenticationException;
import org.keycloak.adapters.springsecurity.account.KeycloakRole;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationFailureHandler;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.KeycloakUriBuilder;
@@ -89,6 +90,8 @@ public class KeycloakAuthenticationProcessingFilterTest {
@Mock
private AuthenticationFailureHandler failureHandler;
private KeycloakAuthenticationFailureHandler keycloakFailureHandler;
@Mock
private OidcKeycloakAccount keycloakAccount;
@@ -106,6 +109,7 @@ public class KeycloakAuthenticationProcessingFilterTest {
MockitoAnnotations.initMocks(this);
request = spy(new MockHttpServletRequest());
filter = new KeycloakAuthenticationProcessingFilter(authenticationManager);
keycloakFailureHandler = new KeycloakAuthenticationFailureHandler();
filter.setApplicationContext(applicationContext);
filter.setAuthenticationSuccessHandler(successHandler);
@@ -155,8 +159,8 @@ public class KeycloakAuthenticationProcessingFilterTest {
when(keycloakDeployment.getStateCookieName()).thenReturn("kc-cookie");
when(keycloakDeployment.getSslRequired()).thenReturn(SslRequired.NONE);
when(keycloakDeployment.isBearerOnly()).thenReturn(Boolean.FALSE);
filter.attemptAuthentication(request, response);
filter.attemptAuthentication(request, response);
verify(response).setStatus(302);
verify(response).setHeader(eq("Location"), startsWith("http://localhost:8080/auth"));
}
@@ -167,6 +171,13 @@ public class KeycloakAuthenticationProcessingFilterTest {
filter.attemptAuthentication(request, response);
}
@Test(expected = KeycloakAuthenticationException.class)
public void testAttemptAuthenticationWithInvalidTokenBearerOnly() throws Exception {
when(keycloakDeployment.isBearerOnly()).thenReturn(Boolean.TRUE);
request.addHeader("Authorization", "Bearer xxx");
filter.attemptAuthentication(request, response);
}
@Test
public void testSuccessfulAuthenticationInteractive() throws Exception {
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, authorities);
@@ -210,8 +221,7 @@ public class KeycloakAuthenticationProcessingFilterTest {
AuthenticationException exception = new BadCredentialsException("OOPS");
this.setBearerAuthHeader(request);
filter.unsuccessfulAuthentication(request, response, exception);
verify(response).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), anyString());
verify(failureHandler, never()).onAuthenticationFailure(any(HttpServletRequest.class), any(HttpServletResponse.class),
verify(failureHandler).onAuthenticationFailure(any(HttpServletRequest.class), any(HttpServletResponse.class),
any(AuthenticationException.class));
}
@@ -220,10 +230,18 @@ public class KeycloakAuthenticationProcessingFilterTest {
AuthenticationException exception = new BadCredentialsException("OOPS");
this.setBasicAuthHeader(request);
filter.unsuccessfulAuthentication(request, response, exception);
verify(response).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), anyString());
verify(failureHandler, never()).onAuthenticationFailure(any(HttpServletRequest.class), any(HttpServletResponse.class),
verify(failureHandler).onAuthenticationFailure(any(HttpServletRequest.class), any(HttpServletResponse.class),
any(AuthenticationException.class));
}
@Test
public void testDefaultFailureHanlder() throws Exception {
AuthenticationException exception = new BadCredentialsException("OOPS");
filter.setAuthenticationFailureHandler(keycloakFailureHandler);
filter.unsuccessfulAuthentication(request, response, exception);
verify(response).sendError(eq(HttpServletResponse.SC_UNAUTHORIZED), any(String.class));
}
@Test(expected = UnsupportedOperationException.class)
public void testSetAllowSessionCreation() throws Exception {
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -76,7 +76,7 @@ public class ElytronSessionTokenStore implements ElytronTokeStore {
public boolean isCached(RequestAuthenticator authenticator) {
HttpScope session = this.httpFacade.getScope(Scope.SESSION);
if (session == null) {
if (session == null || !session.supportsAttachments()) {
log.debug("session was null, returning null");
return false;
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -124,6 +124,12 @@ public class SharedAttributeDefinitons {
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CORS_EXPOSED_HEADERS =
new SimpleAttributeDefinitionBuilder("cors-exposed-headers", ModelType.STRING, true)
.setXmlName("cors-exposed-headers")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
.setXmlName("expose-token")
@@ -172,7 +178,14 @@ public class SharedAttributeDefinitons {
.setXmlName("autodetect-bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
.build();
protected static final SimpleAttributeDefinition IGNORE_OAUTH_QUERY_PARAMETER =
new SimpleAttributeDefinitionBuilder("ignore-oauth-query-parameter", ModelType.BOOLEAN, true)
.setXmlName("ignore-oauth-query-parameter")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
@@ -191,6 +204,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(CORS_MAX_AGE);
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
ATTRIBUTES.add(CORS_EXPOSED_HEADERS);
ATTRIBUTES.add(EXPOSE_TOKEN);
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
@@ -199,6 +213,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(TOKEN_STORE);
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER);
}
/**
@@ -39,6 +39,7 @@ keycloak.realm.client-key-password=n/a
keycloak.realm.cors-max-age=CORS max-age header
keycloak.realm.cors-allowed-headers=CORS allowed headers
keycloak.realm.cors-allowed-methods=CORS allowed methods
keycloak.realm.cors-exposed-headers=CORS exposed headers
keycloak.realm.expose-token=Enable secure URL that exposes access token
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.realm.always-refresh-token=Refresh token on every single web request
@@ -47,6 +48,7 @@ keycloak.realm.register-node-period=how often to re-register node
keycloak.realm.token-store=cookie or session storage for auth session data
keycloak.realm.principal-attribute=token attribute to use to set Principal name
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
@@ -73,6 +75,7 @@ keycloak.secure-deployment.client-key-password=n/a
keycloak.secure-deployment.cors-max-age=CORS max-age header
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
keycloak.secure-deployment.cors-exposed-headers=CORS exposed headers
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
@@ -84,6 +87,7 @@ keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-deployment.credential=Credential value
@@ -58,6 +58,7 @@
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -66,6 +67,7 @@
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -88,6 +90,7 @@
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
@@ -109,6 +112,7 @@
<xs:element name="token-minimum-time-to-live" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="min-time-between-jwks-requests" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -37,6 +37,8 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD
public final class KeycloakAdapterConfigService {
private static final String CREDENTIALS_JSON_NAME = "credentials";
private static final String REDIRECT_REWRITE_RULE_JSON_NAME = "redirect-rewrite-rule";
private static final KeycloakAdapterConfigService INSTANCE = new KeycloakAdapterConfigService();
@@ -129,6 +131,56 @@ public final class KeycloakAdapterConfigService {
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
return deployment.get(CREDENTIALS_JSON_NAME);
}
public void addRedirectRewriteRule(ModelNode operation, ModelNode model) {
ModelNode redirectRewritesRules = redirectRewriteRuleFromOp(operation);
if (!redirectRewritesRules.isDefined()) {
redirectRewritesRules = new ModelNode();
}
String redirectRewriteRuleName = redirectRewriteRule(operation);
if (!redirectRewriteRuleName.contains(".")) {
redirectRewritesRules.get(redirectRewriteRuleName).set(model.get("value").asString());
} else {
String[] parts = redirectRewriteRuleName.split("\\.");
String provider = parts[0];
String property = parts[1];
ModelNode redirectRewriteRule = redirectRewritesRules.get(provider);
if (!redirectRewriteRule.isDefined()) {
redirectRewriteRule = new ModelNode();
}
redirectRewriteRule.get(property).set(model.get("value").asString());
redirectRewritesRules.set(provider, redirectRewriteRule);
}
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
deployment.get(REDIRECT_REWRITE_RULE_JSON_NAME).set(redirectRewritesRules);
}
public void removeRedirectRewriteRule(ModelNode operation) {
ModelNode redirectRewritesRules = redirectRewriteRuleFromOp(operation);
if (!redirectRewritesRules.isDefined()) {
throw new RuntimeException("Can not remove redirect rewrite rule. No rules defined for deployment in op " + operation.toString());
}
String ruleName = credentialNameFromOp(operation);
redirectRewritesRules.remove(ruleName);
}
public void updateRedirectRewriteRule(ModelNode operation, String attrName, ModelNode resolvedValue) {
ModelNode redirectRewritesRules = redirectRewriteRuleFromOp(operation);
if (!redirectRewritesRules.isDefined()) {
throw new RuntimeException("Can not update redirect rewrite rule. No rules defined for deployment in op " + operation.toString());
}
String ruleName = credentialNameFromOp(operation);
redirectRewritesRules.get(ruleName).set(resolvedValue);
}
private ModelNode redirectRewriteRuleFromOp(ModelNode operation) {
ModelNode deployment = this.secureDeployments.get(deploymentNameFromOp(operation));
return deployment.get(REDIRECT_REWRITE_RULE_JSON_NAME);
}
private String realmNameFromOp(ModelNode operation) {
return valueFromOpAddress(RealmDefinition.TAG_NAME, operation);
@@ -141,6 +193,10 @@ public final class KeycloakAdapterConfigService {
private String credentialNameFromOp(ModelNode operation) {
return valueFromOpAddress(CredentialDefinition.TAG_NAME, operation);
}
private String redirectRewriteRule(ModelNode operation) {
return valueFromOpAddress(RedirecRewritetRuleDefinition.TAG_NAME, operation);
}
private String valueFromOpAddress(String addrElement, ModelNode operation) {
String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
@@ -48,6 +48,7 @@ public class KeycloakExtension implements Extension {
static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
static final RedirecRewritetRuleDefinition REDIRECT_RULE_DEFINITON = new RedirecRewritetRuleDefinition();
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
@@ -77,6 +78,7 @@ public class KeycloakExtension implements Extension {
registration.registerSubModel(REALM_DEFINITION);
ManagementResourceRegistration secureDeploymentRegistration = registration.registerSubModel(SECURE_DEPLOYMENT_DEFINITION);
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
secureDeploymentRegistration.registerSubModel(REDIRECT_RULE_DEFINITON);
subsystem.registerXMLElementWriter(PARSER);
}
@@ -96,12 +96,17 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
List<ModelNode> redirectRulesToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String tagName = reader.getLocalName();
if (tagName.equals(CredentialDefinition.TAG_NAME)) {
readCredential(reader, addr, credentialsToAdd);
continue;
}
if (tagName.equals(RedirecRewritetRuleDefinition.TAG_NAME)) {
readRewriteRule(reader, addr, redirectRulesToAdd);
continue;
}
SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
@@ -111,6 +116,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
// Must add credentials after the deployment is added.
resourcesToAdd.add(addSecureDeployment);
resourcesToAdd.addAll(credentialsToAdd);
resourcesToAdd.addAll(redirectRulesToAdd);
}
public void readCredential(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> credentialsToAdd) throws XMLStreamException {
@@ -149,6 +155,43 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
}
}
}
public void readRewriteRule(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> rewriteRuleToToAdd) throws XMLStreamException {
String name = readNameAttribute(reader);
Map<String, String> values = new HashMap<>();
String textValue = null;
while (reader.hasNext()) {
int next = reader.next();
if (next == CHARACTERS) {
// text value of redirect rule element
String text = reader.getText();
if (text == null || text.trim().isEmpty()) {
continue;
}
textValue = text;
} else if (next == START_ELEMENT) {
String key = reader.getLocalName();
reader.next();
String value = reader.getText();
reader.next();
values.put(key, value);
} else if (next == END_ELEMENT) {
break;
}
}
if (textValue != null) {
ModelNode addRedirectRule = getRedirectRuleToAdd(parent, name, textValue);
rewriteRuleToToAdd.add(addRedirectRule);
} else {
for (Map.Entry<String, String> entry : values.entrySet()) {
ModelNode addRedirectRule = getRedirectRuleToAdd(parent, name + "." + entry.getKey(), entry.getValue());
rewriteRuleToToAdd.add(addRedirectRule);
}
}
}
private ModelNode getCredentialToAdd(PathAddress parent, String name, String value) {
ModelNode addCredential = new ModelNode();
@@ -158,6 +201,15 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
addCredential.get(CredentialDefinition.VALUE.getName()).set(value);
return addCredential;
}
private ModelNode getRedirectRuleToAdd(PathAddress parent, String name, String value) {
ModelNode addRedirectRule = new ModelNode();
addRedirectRule.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(parent, PathElement.pathElement(RedirecRewritetRuleDefinition.TAG_NAME, name));
addRedirectRule.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
addRedirectRule.get(RedirecRewritetRuleDefinition.VALUE.getName()).set(value);
return addRedirectRule;
}
// expects that the current tag will have one single attribute called "name"
private String readNameAttribute(XMLExtendedStreamReader reader) throws XMLStreamException {
@@ -219,6 +271,11 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (credentials.isDefined()) {
writeCredentials(writer, credentials);
}
ModelNode redirectRewriteRule = deploymentElements.get(RedirecRewritetRuleDefinition.TAG_NAME);
if (redirectRewriteRule.isDefined()) {
writeRedirectRules(writer, redirectRewriteRule);
}
writer.writeEndElement();
}
@@ -265,6 +322,34 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
writer.writeEndElement();
}
}
private void writeRedirectRules(XMLExtendedStreamWriter writer, ModelNode redirectRules) throws XMLStreamException {
Map<String, Object> parsed = new LinkedHashMap<>();
for (Property redirectRule : redirectRules.asPropertyList()) {
String ruleName = redirectRule.getName();
String ruleValue = redirectRule.getValue().get(RedirecRewritetRuleDefinition.VALUE.getName()).asString();
parsed.put(ruleName, ruleValue);
}
for (Map.Entry<String, Object> entry : parsed.entrySet()) {
writer.writeStartElement(RedirecRewritetRuleDefinition.TAG_NAME);
writer.writeAttribute("name", entry.getKey());
Object value = entry.getValue();
if (value instanceof String) {
writeCharacters(writer, (String) value);
} else {
Map<String, String> redirectRulesProps = (Map<String, String>) value;
for (Map.Entry<String, String> prop : redirectRulesProps.entrySet()) {
writer.writeStartElement(prop.getKey());
writeCharacters(writer, prop.getValue());
writer.writeEndElement();
}
}
writer.writeEndElement();
}
}
// code taken from org.jboss.as.controller.AttributeMarshaller
private void writeCharacters(XMLExtendedStreamWriter writer, String content) throws XMLStreamException {
@@ -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.subsystem.adapter.extension;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelType;
/**
*
* @author sblanc
*/
public class RedirecRewritetRuleDefinition extends SimpleResourceDefinition {
public static final String TAG_NAME = "redirect-rewrite-rule";
protected static final AttributeDefinition VALUE =
new SimpleAttributeDefinitionBuilder("value", ModelType.STRING, false)
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, false, true))
.build();
public RedirecRewritetRuleDefinition() {
super(PathElement.pathElement(TAG_NAME),
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
new RedirectRewriteRuleAddHandler(VALUE),
RedirectRewriteRuleRemoveHandler.INSTANCE);
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
resourceRegistration.registerReadWriteAttribute(VALUE, null, new RedirectRewriteRuleReadWriteAttributeHandler());
}
}
@@ -0,0 +1,38 @@
/*
* 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.subsystem.adapter.extension;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
public class RedirectRewriteRuleAddHandler extends AbstractAddStepHandler {
public RedirectRewriteRuleAddHandler(AttributeDefinition... attributes) {
super(attributes);
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.addRedirectRewriteRule(operation, context.resolveExpressions(model));
}
}
@@ -0,0 +1,44 @@
/*
* 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.subsystem.adapter.extension;
import org.jboss.as.controller.AbstractWriteAttributeHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
public class RedirectRewriteRuleReadWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
@Override
protected boolean applyUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode resolvedValue, ModelNode currentValue, AbstractWriteAttributeHandler.HandbackHolder<KeycloakAdapterConfigService> hh) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.updateRedirectRewriteRule(operation, attributeName, resolvedValue);
hh.setHandback(ckService);
return false;
}
@Override
protected void revertUpdateToRuntime(OperationContext context, ModelNode operation, String attributeName,
ModelNode valueToRestore, ModelNode valueToRevert, KeycloakAdapterConfigService ckService) throws OperationFailedException {
ckService.updateRedirectRewriteRule(operation, attributeName, valueToRestore);
}
}
@@ -0,0 +1,36 @@
/*
* 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.subsystem.adapter.extension;
import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.dmr.ModelNode;
public class RedirectRewriteRuleRemoveHandler extends AbstractRemoveStepHandler {
public static RedirectRewriteRuleRemoveHandler INSTANCE = new RedirectRewriteRuleRemoveHandler();
private RedirectRewriteRuleRemoveHandler() {}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.removeRedirectRewriteRule(operation);
}
}
@@ -124,6 +124,12 @@ public class SharedAttributeDefinitons {
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition CORS_EXPOSED_HEADERS =
new SimpleAttributeDefinitionBuilder("cors-exposed-headers", ModelType.STRING, true)
.setXmlName("cors-exposed-headers")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
.setXmlName("expose-token")
@@ -173,6 +179,14 @@ public class SharedAttributeDefinitons {
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition IGNORE_OAUTH_QUERY_PARAMETER =
new SimpleAttributeDefinitionBuilder("ignore-oauth-query-parameter", ModelType.BOOLEAN, true)
.setXmlName("ignore-oauth-query-parameter")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
@@ -192,6 +206,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(CORS_MAX_AGE);
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
ATTRIBUTES.add(CORS_EXPOSED_HEADERS);
ATTRIBUTES.add(EXPOSE_TOKEN);
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
@@ -200,6 +215,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(TOKEN_STORE);
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
ATTRIBUTES.add(IGNORE_OAUTH_QUERY_PARAMETER);
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
@@ -39,6 +39,7 @@ keycloak.realm.client-key-password=n/a
keycloak.realm.cors-max-age=CORS max-age header
keycloak.realm.cors-allowed-headers=CORS allowed headers
keycloak.realm.cors-allowed-methods=CORS allowed methods
keycloak.realm.cors-exposed-headers=CORS exposed headers
keycloak.realm.expose-token=Enable secure URL that exposes access token
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.realm.always-refresh-token=Refresh token on every single web request
@@ -47,6 +48,7 @@ keycloak.realm.register-node-period=how often to re-register node
keycloak.realm.token-store=cookie or session storage for auth session data
keycloak.realm.principal-attribute=token attribute to use to set Principal name
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
keycloak.realm.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
@@ -63,6 +65,7 @@ keycloak.secure-deployment.connection-pool-size=Connection pool size for the cli
keycloak.secure-deployment.resource=Application name
keycloak.secure-deployment.use-resource-role-mappings=Use resource level permissions from token
keycloak.secure-deployment.credentials=Adapter credentials
keycloak.secure-deployment.redirect-rewrite-rule=Apply a rewrite rule for the redirect URI
keycloak.secure-deployment.bearer-only=Bearer Token Auth only
keycloak.secure-deployment.enable-basic-auth=Enable Basic Authentication
keycloak.secure-deployment.public-client=Public client
@@ -74,6 +77,7 @@ keycloak.secure-deployment.client-key-password=n/a
keycloak.secure-deployment.cors-max-age=CORS max-age header
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
keycloak.secure-deployment.cors-exposed-headers=CORS exposed headers
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
@@ -84,10 +88,16 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-deployment.credential=Credential value
keycloak.credential=Credential
keycloak.credential.value=Credential value
keycloak.credential.add=Credential add
keycloak.credential.remove=Credential remove
keycloak.credential.remove=Credential remove
keycloak.redirect-rewrite-rule=redirect-rewrite-rule
keycloak.redirect-rewrite-rule.value=redirect-rewrite-rule value
keycloak.redirect-rewrite-rule.add=redirect-rewrite-rule add
keycloak.redirect-rewrite-rule.remove=redirect-rewrite-rule remove
@@ -58,6 +58,7 @@
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -66,6 +67,7 @@
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -88,6 +90,7 @@
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
@@ -98,6 +101,7 @@
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="credential" type="credential-type" minOccurs="1" maxOccurs="1"/>
<xs:element name="redirect-rewrite-rule" type="redirect-rewrite-rule-type" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="register-node-at-startup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -109,6 +113,7 @@
<xs:element name="token-minimum-time-to-live" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="min-time-between-jwks-requests" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="ignore-oauth-query-parameter" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -123,4 +128,10 @@
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="redirect-rewrite-rule-type" mixed="true">
<xs:sequence maxOccurs="unbounded" minOccurs="0">
<xs:any processContents="lax"></xs:any>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
</xs:schema>
@@ -53,6 +53,7 @@
<auth-server-url>http://localhost:8080/auth</auth-server-url>
<ssl-required>EXTERNAL</ssl-required>
<credential name="secret">0aa31d98-e0aa-404c-b6e0-e771dba1e798</credential>
<redirect-rewrite-rule name="^/wsmaster/api/(.*)$">api/$1/</redirect-rewrite-rule>
</secure-deployment>
<secure-deployment name="http-endpoint">
<realm>master</realm>
@@ -66,5 +67,6 @@
<credential name="jwt">
<client-keystore-file>/tmp/keystore.jks</client-keystore-file>
</credential>
<redirect-rewrite-rule name="^/wsmaster/api/(.*)$">/api/$1/</redirect-rewrite-rule>
</secure-deployment>
</subsystem>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -294,6 +294,7 @@ public class DefaultSamlDeployment implements SamlDeployment {
private String logoutPage;
private SignatureAlgorithm signatureAlgorithm;
private String signatureCanonicalizationMethod;
private boolean autodetectBearerOnly;
@Override
public boolean turnOffChangeSessionIdOnLogin() {
@@ -439,4 +440,13 @@ public class DefaultSamlDeployment implements SamlDeployment {
public void setSignatureAlgorithm(SignatureAlgorithm signatureAlgorithm) {
this.signatureAlgorithm = signatureAlgorithm;
}
@Override
public boolean isAutodetectBearerOnly() {
return autodetectBearerOnly;
}
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
this.autodetectBearerOnly = autodetectBearerOnly;
}
}
@@ -168,6 +168,6 @@ public interface SamlDeployment {
}
PrincipalNamePolicy getPrincipalNamePolicy();
String getPrincipalAttributeName();
boolean isAutodetectBearerOnly();
}
@@ -58,6 +58,7 @@ public class SP implements Serializable {
private PrincipalNameMapping principalNameMapping;
private Set<String> roleAttributes;
private IDP idp;
private boolean autodetectBearerOnly;
public String getEntityID() {
return entityID;
@@ -147,4 +148,11 @@ public class SP implements Serializable {
this.logoutPage = logoutPage;
}
public boolean isAutodetectBearerOnly() {
return autodetectBearerOnly;
}
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
this.autodetectBearerOnly = autodetectBearerOnly;
}
}
@@ -33,6 +33,7 @@ public class ConfigXmlConstants {
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";
@@ -68,6 +68,7 @@ public class DeploymentBuilder {
deployment.setNameIDPolicyFormat(sp.getNameIDPolicyFormat());
deployment.setLogoutPage(sp.getLogoutPage());
deployment.setSignatureCanonicalizationMethod(sp.getIdp().getSignatureCanonicalizationMethod());
deployment.setAutodetectBearerOnly(sp.isAutodetectBearerOnly());
deployment.setSignatureAlgorithm(SignatureAlgorithm.RSA_SHA256);
if (sp.getIdp().getSignatureAlgorithm() != null) {
deployment.setSignatureAlgorithm(SignatureAlgorithm.valueOf(sp.getIdp().getSignatureAlgorithm()));
@@ -89,6 +89,7 @@ public class SPXmlParser extends AbstractParser {
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);
@@ -34,6 +34,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.DocumentUtil;
import org.keycloak.saml.processing.core.util.NamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -65,9 +66,7 @@ public class SamlDescriptorIDPKeysExtractor {
MultivaluedHashMap<String, KeyInfo> res = new MultivaluedHashMap<>();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
DocumentBuilder builder = DocumentUtil.getDocumentBuilder();
Document doc = builder.parse(stream);
XPathExpression expr = xpath.compile("/m:EntitiesDescriptor/m:EntityDescriptor/m:IDPSSODescriptor/m:KeyDescriptor");
@@ -53,10 +53,12 @@ import org.keycloak.saml.SAML2AuthnRequestBuilder;
import org.keycloak.saml.SAMLRequestParser;
import org.keycloak.saml.SignatureAlgorithm;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ProcessingException;
import org.keycloak.saml.common.util.Base64;
import org.keycloak.saml.common.util.DocumentUtil;
import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
@@ -74,10 +76,14 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.*;
import javax.xml.namespace.QName;
import org.keycloak.dom.saml.v2.SAML2Object;
import org.keycloak.dom.saml.v2.protocol.ExtensionsType;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
/**
*
@@ -210,7 +216,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
return AuthOutcome.FAILED;
}
}
return handleLoginResponse((ResponseType) statusResponse, postBinding, onCreateSession);
return handleLoginResponse(holder, postBinding, onCreateSession);
} finally {
sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
}
@@ -312,7 +318,8 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
return false;
}
protected AuthOutcome handleLoginResponse(final ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
protected AuthOutcome handleLoginResponse(SAMLDocumentHolder responseHolder, boolean postBinding, OnSessionCreated onCreateSession) {
final ResponseType responseType = (ResponseType) responseHolder.getSamlObject();
AssertionType assertion = null;
if (! isSuccessfulSamlResponse(responseType) || responseType.getAssertions() == null || responseType.getAssertions().isEmpty()) {
challenge = new AuthChallenge() {
@@ -357,14 +364,33 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
if (deployment.getIDP().getSingleSignOnService().validateAssertionSignature()) {
try {
validateSamlSignature(new SAMLDocumentHolder(AssertionUtil.asDocument(assertion)), postBinding, GeneralConstants.SAML_RESPONSE_KEY);
} catch (VerificationException e) {
log.error("Failed to verify saml assertion signature", e);
if (!AssertionUtil.isSignatureValid(getAssertionFromResponse(responseHolder), deployment.getIDP().getSignatureValidationKeyLocator())) {
log.error("Failed to verify saml assertion signature");
challenge = new AuthChallenge() {
@Override
public boolean challenge(HttpFacade exchange) {
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE, responseType);
exchange.getRequest().setError(error);
exchange.getResponse().sendError(403);
return true;
}
@Override
public int getResponseCode() {
return 403;
}
};
return AuthOutcome.FAILED;
}
} catch (Exception e) {
log.error("Error processing validation of SAML assertion: " + e.getMessage());
challenge = new AuthChallenge() {
@Override
public boolean challenge(HttpFacade exchange) {
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE, responseType);
SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.EXTRACTION_FAILURE);
exchange.getRequest().setError(error);
exchange.getResponse().sendError(403);
return true;
@@ -376,8 +402,6 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
}
};
return AuthOutcome.FAILED;
} catch (ProcessingException e) {
e.printStackTrace();
}
}
@@ -480,6 +504,18 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
&& Objects.equals(responseType.getStatus().getStatusCode().getValue().toString(), JBossSAMLURIConstants.STATUS_SUCCESS.get());
}
private Element getAssertionFromResponse(final SAMLDocumentHolder responseHolder) throws ConfigurationException, ProcessingException {
Element encryptedAssertion = DocumentUtil.getElement(responseHolder.getSamlDocument(), new QName(JBossSAMLConstants.ENCRYPTED_ASSERTION.get()));
if (encryptedAssertion != null) {
// encrypted assertion.
// We'll need to decrypt it first.
Document encryptedAssertionDocument = DocumentUtil.createDocument();
encryptedAssertionDocument.appendChild(encryptedAssertionDocument.importNode(encryptedAssertion, true));
return XMLEncryptionUtil.decryptElementInDocument(encryptedAssertionDocument, deployment.getDecryptionKey());
}
return DocumentUtil.getElement(responseHolder.getSamlDocument(), new QName(JBossSAMLConstants.ASSERTION.get()));
}
private String getAttributeValue(Object attrValue) {
String value = null;
if (attrValue instanceof String) {
@@ -529,9 +565,15 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
return new AbstractInitiateLogin(deployment, sessionStore) {
@Override
protected void sendAuthnRequest(HttpFacade httpFacade, SAML2AuthnRequestBuilder authnRequestBuilder, BaseSAML2BindingBuilder binding) throws ProcessingException, ConfigurationException, IOException {
Document document = authnRequestBuilder.toDocument();
SamlDeployment.Binding samlBinding = deployment.getIDP().getSingleSignOnService().getRequestBinding();
SamlUtil.sendSaml(true, httpFacade, deployment.getIDP().getSingleSignOnService().getRequestBindingUrl(), binding, document, samlBinding);
if (isAutodetectedBearerOnly(httpFacade.getRequest())) {
httpFacade.getResponse().setStatus(401);
httpFacade.getResponse().end();
}
else {
Document document = authnRequestBuilder.toDocument();
SamlDeployment.Binding samlBinding = deployment.getIDP().getSingleSignOnService().getRequestBinding();
SamlUtil.sendSaml(true, httpFacade, deployment.getIDP().getSingleSignOnService().getRequestBindingUrl(), binding, document, samlBinding);
}
}
};
}
@@ -654,4 +696,34 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
return signature.verify(decodedSignature);
}
protected boolean isAutodetectedBearerOnly(HttpFacade.Request request) {
if (!deployment.isAutodetectBearerOnly()) return false;
String headerValue = facade.getRequest().getHeader(GeneralConstants.HTTP_HEADER_X_REQUESTED_WITH);
if (headerValue != null && headerValue.equalsIgnoreCase("XMLHttpRequest")) {
return true;
}
headerValue = facade.getRequest().getHeader("Faces-Request");
if (headerValue != null && headerValue.startsWith("partial/")) {
return true;
}
headerValue = facade.getRequest().getHeader("SOAPAction");
if (headerValue != null) {
return true;
}
List<String> accepts = facade.getRequest().getHeaders("Accept");
if (accepts == null) accepts = Collections.emptyList();
for (String accept : accepts) {
if (accept.contains("text/html") || accept.contains("text/*") || accept.contains("*/*")) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,461 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:keycloak:saml:adapter"
targetNamespace="urn:keycloak:saml:adapter"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="keycloak-saml-adapter" type="adapter-type"/>
<xs:complexType name="adapter-type">
<xs:annotation>
<xs:documentation>Keycloak SAML Adapter configuration file.</xs:documentation>
</xs:annotation>
<xs:all>
<xs:element name="SP" maxOccurs="1" minOccurs="0" type="sp-type">
<xs:annotation>
<xs:documentation>Describes SAML service provider configuration.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
</xs:complexType>
<xs:complexType name="sp-type">
<xs:all>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
List of service provider encryption and validation keys.
If the IDP requires that the client application (SP) sign all of its requests and/or if the IDP will encrypt assertions, you must define the keys used to do this. For client signed documents you must define both the private and public key or certificate that will be used to sign documents. For encryption, you only have to define the private key that will be used to decrypt.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PrincipalNameMapping" type="principal-name-mapping-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>When creating a Java Principal object that you obtain from methods like HttpServletRequest.getUserPrincipal(), you can define what name that is returned by the Principal.getName() method.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="RoleIdentifiers" type="role-identifiers-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Defines what SAML attributes within the assertion received from the user should be used as role identifiers within the Java EE Security Context for the user.
By default Role attribute values are converted to Java EE roles. Some IDPs send roles via a member or memberOf attribute assertion. You can define one or more Attribute elements to specify which SAML attributes must be converted into roles.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="IDP" type="idp-type" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:documentation>Describes configuration of SAML identity provider for this service provider.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="entityID" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>This is the identifier for this client. The IDP needs this value to determine who the client is that is communicating with it.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="sslPolicy" type="ssl-policy-type" use="optional">
<xs:annotation>
<xs:documentation>SSL policy the adapter will enforce.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="nameIDPolicyFormat" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request a specific NameID Subject format. Fill in this value if you want a specific format. It must be a standard SAML format identifier, i.e. urn:oasis:names:tc:SAML:2.0:nameid-format:transient. By default, no special format is requested.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="logoutPage" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>URL of the logout page.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="forceAuthentication" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request that a user is re-authenticated even if they are already logged in at the IDP. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="isPassive" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>SAML clients can request that a user is never asked to authenticate even if they are not logged in at the IDP. Set this to true if you want this. Do not use together with forceAuthentication as they are opposite. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="turnOffChangeSessionIdOnLogin" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>The session id is changed by default on a successful login on some platforms to plug a security attack vector. Change this to true to disable this. It is recommended you do not turn it off. Default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="autodetectBearerOnly" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>This should be set to true if your application serves both a web application and web services (e.g. SOAP or REST). It allows you to redirect unauthenticated users of the web application to the Keycloak login page, but send an HTTP 401 status code to unauthenticated SOAP or REST clients instead as they would not understand a redirect to the login page. Keycloak auto-detects SOAP or REST clients based on typical headers like X-Requested-With, SOAPAction or Accept. The default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="keys-type">
<xs:sequence>
<xs:element name="Key" type="key-type" minOccurs="1" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>Describes a single key used for signing or encryption.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="key-type">
<xs:all>
<xs:element name="KeyStore" maxOccurs="1" minOccurs="0" type="key-store-type">
<xs:annotation>
<xs:documentation>Java keystore to load keys and certificates from.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PrivateKeyPem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Private key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="PublicKeyPem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Public key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="CertificatePem" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Certificate key (PEM format)</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="signing" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Flag defining whether the key should be used for signing.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="encryption" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Flag defining whether the key should be used for encryption</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="key-store-type">
<xs:all>
<xs:element name="PrivateKey" maxOccurs="1" minOccurs="0" type="private-key-type">
<xs:annotation>
<xs:documentation>Private key declaration</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Certificate" type="certificate-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Certificate declaration</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="file" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>File path to the key store.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="resource" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>WAR resource path to the key store. This is a path used in method call to ServletContext.getResourceAsStream().</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>The password of the key store.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="private-key-type">
<xs:attribute name="alias" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Alias that points to the key or cert within the keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="password" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Keystores require an additional password to access private keys. In the PrivateKey element you must define this password within a password attribute.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="certificate-type">
<xs:attribute name="alias" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Alias that points to the key or cert within the keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="principal-name-mapping-type">
<xs:attribute name="policy" type="principal-name-mapping-policy-type" use="required">
<xs:annotation>
<xs:documentation>Policy used to populate value of Java Principal object obtained from methods like HttpServletRequest.getUserPrincipal().</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="attribute" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Name of the SAML assertion attribute to use within.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:simpleType name="principal-name-mapping-policy-type">
<xs:restriction base="xs:string">
<xs:enumeration value="FROM_NAME_ID">
<xs:annotation>
<xs:documentation>This policy just uses whatever the SAML subject value is. This is the default setting</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="FROM_ATTRIBUTE">
<xs:annotation>
<xs:documentation>This will pull the value from one of the attributes declared in the SAML assertion received from the server. You'll need to specify the name of the SAML assertion attribute to use within the attribute XML attribute.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ssl-policy-type">
<xs:restriction base="xs:string">
<xs:enumeration value="ALL">
<xs:annotation>
<xs:documentation>All requests must come in via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="EXTERNAL">
<xs:annotation>
<xs:documentation>Only non-private IP addresses must come over the wire via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="NONE">
<xs:annotation>
<xs:documentation>no requests are required to come over via HTTPS.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="signature-algorithm-type">
<xs:restriction base="xs:string">
<xs:enumeration value="RSA_SHA1"/>
<xs:enumeration value="RSA_SHA256"/>
<xs:enumeration value="RSA_SHA512"/>
<xs:enumeration value="DSA_SHA1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="binding-type">
<xs:restriction base="xs:string">
<xs:enumeration value="POST"/>
<xs:enumeration value="REDIRECT"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="role-identifiers-type">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Attribute" maxOccurs="unbounded" minOccurs="0" type="attribute-type">
<xs:annotation>
<xs:documentation>Specifies SAML attribute to be converted into roles.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:complexType name="attribute-type">
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>Specifies name of the SAML attribute to be converted into roles.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="idp-type">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="SingleSignOnService" maxOccurs="1" minOccurs="1" type="sign-on-type">
<xs:annotation>
<xs:documentation>Configuration of the login SAML endpoint of the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SingleLogoutService" type="logout-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Configuration of the logout SAML endpoint of the IDP</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Keys" type="keys-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>The Keys sub element of IDP is only used to define the certificate or public key to use to verify documents signed by the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="HttpClient" type="http-client-type" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Configuration of HTTP client used for automatic obtaining of certificates containing public keys for IDP signature verification via SAML descriptor of the IDP.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="entityID" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>issuer ID of the IDP.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signaturesRequired" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>If set to true, the client adapter will sign every document it sends to the IDP. Also, the client will expect that the IDP will be signing any documents sent to it. This switch sets the default for all request and response types.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signatureAlgorithm" type="signature-algorithm-type" use="optional">
<xs:annotation>
<xs:documentation>Signature algorithm that the IDP expects signed documents to use. Defaults to RSA_SHA256</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signatureCanonicalizationMethod" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the signature canonicalization method that the IDP expects signed documents to use. The default value is https://www.w3.org/2001/10/xml-exc-c14n# and should be good for most IDPs.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="encryption" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation></xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="sign-on-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign authn requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect the IDP to sign the assertion response document sent back from an auhtn request? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect the IDP to sign the individual assertions sent back from an auhtn request? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="requestBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>SAML binding type used for communicating with the IDP. The default value is POST, but you can set it to REDIRECT as well.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="responseBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>SAML allows the client to request what binding type it wants authn responses to use. This value maps to ProtocolBinding attribute in SAML AuthnRequest. The default is that the client will not request a specific binding type for responses.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="bindingUrl" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>This is the URL for the IDP login service that the client will send requests to.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="assertionConsumerServiceUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>URL of the assertion consumer service (ACS) where the IDP login service should send responses to. By default it is unset, relying on the IdP settings. When set, it must end in "/saml". This property is typically accompanied by the responseBinding attribute.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="logout-type">
<xs:attribute name="signRequest" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign authn requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="signResponse" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client sign logout responses it sends to the IDP requests? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect signed logout request documents from the IDP? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional">
<xs:annotation>
<xs:documentation>Should the client expect signed logout response documents from the IDP? Defaults to whatever the IDP signaturesRequired element value is.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="requestBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>This is the SAML binding type used for communicating SAML requests to the IDP. The default value is POST.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="responseBinding" type="binding-type" use="optional">
<xs:annotation>
<xs:documentation>This is the SAML binding type used for communicating SAML responses to the IDP. The default value is POST.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="postBindingUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the URL for the IDP's logout service when using the POST binding. This setting is REQUIRED if using the POST binding.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="redirectBindingUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the URL for the IDP's logout service when using the REDIRECT binding. This setting is REQUIRED if using the REDIRECT binding.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="http-client-type">
<xs:attribute name="allowAnyHostname" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>If the the IDP server requires HTTPS and this config option is set to true the IDP's certificate
is validated via the truststore, but host name validation is not done. This setting should only be used during
development and never in production as it will partly disable verification of SSL certificates.
This seting may be useful in test environments. The default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="clientKeystore" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>This is the file path to a keystore file. This keystore contains client certificate
for two-way SSL when the adapter makes HTTPS requests to the IDP server.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="clientKeystorePassword" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Password for the client keystore and for the client's key.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="connectionPoolSize" type="xs:int" use="optional" default="10">
<xs:annotation>
<xs:documentation>Defines number of pooled connections.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="disableTrustManager" type="xs:boolean" use="optional" default="false">
<xs:annotation>
<xs:documentation>If the the IDP server requires HTTPS and this config option is set to true you do not have to specify a truststore.
This setting should only be used during development and never in production as it will disable verification of SSL certificates.
The default value is false.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="proxyUrl" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>URL to HTTP proxy to use for HTTP connections.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="truststore" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>The value is the file path to a keystore file. If you prefix the path with classpath:,
then the truststore will be obtained from the deployment's classpath instead. Used for outgoing
HTTPS communications to the IDP server. Client making HTTPS requests need
a way to verify the host of the server they are talking to. This is what the trustore does.
The keystore contains one or more trusted host certificates or certificate authorities.
You can create this truststore by extracting the public certificate of the IDP's SSL keystore.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="truststorePassword" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Password for the truststore keystore.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:schema>
@@ -37,7 +37,7 @@ import org.keycloak.saml.common.exceptions.ParsingException;
*/
public class KeycloakSamlAdapterXMLParserTest {
private static final String CURRENT_XSD_LOCATION = "/schema/keycloak_saml_adapter_1_7.xsd";
private static final String CURRENT_XSD_LOCATION = "/schema/keycloak_saml_adapter_1_9.xsd";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -91,6 +91,7 @@ public class KeycloakSamlAdapterXMLParserTest {
assertEquals("format", sp.getNameIDPolicyFormat());
assertTrue(sp.isForceAuthentication());
assertTrue(sp.isIsPassive());
assertFalse(sp.isAutodetectBearerOnly());
assertEquals(2, sp.getKeys().size());
Key signing = sp.getKeys().get(0);
assertTrue(signing.isSigning());
@@ -17,7 +17,7 @@
<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">
xsi:schemaLocation="urn:keycloak:saml:adapter http://www.keycloak.org/schema/keycloak_saml_adapter_1_9.xsd">
<SP entityID="sp"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="format"
@@ -73,4 +73,4 @@
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
</keycloak-saml-adapter>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</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.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Jetty Integration</name>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.CR1-SNAPSHOT</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
Loaded 100 of 1944 files, more files were not shown because too many files have changed in this diff. Show more