Compare commits

..
523 Commits
Author SHA1 Message Date
keycloak-bot 242dc980fc Set version to 3.1.0.Final 2017-05-03 05:45:14 +00:00
vramik b61ffa95cc KEYCLOAK-4819 update product.filename.version 2017-05-02 09:33:41 +02:00
keycloak-bot a809fd2973 Set version to 3.1.0.Final-SNAPSHOT 2017-04-27 14:50:13 +00:00
keycloak-bot da82baec4a Set version to 3.1.0.CR1 2017-04-27 14:09:48 +00:00
Stian Thorgersen 141ffc0ee0 Merge pull request #4094 from sebastienblanc/update_starte_31
rename the starter and spring-boot-starter
2017-04-27 16:08:17 +02:00
sebastienblanc 0828136f01 rename the starter and spring-boot-starter 2017-04-27 16:00:00 +02:00
Stian Thorgersen 6e9b9bedbb Merge pull request #4091 from stianst/master
Fix downloads dist
2017-04-27 14:14:31 +02:00
Stian Thorgersen 57bf9254e1 Fix downloads dist 2017-04-27 14:14:12 +02:00
Stian Thorgersen f0ac725984 Merge pull request #4089 from stianst/master
Fix spring boot starter pom
2017-04-27 12:40:45 +02:00
Stian Thorgersen c0e03c05c7 Fix spring boot starter pom 2017-04-27 12:40:23 +02:00
Stian Thorgersen 14cf2c9aba Merge pull request #4088 from sebastienblanc/KEYCLOAK-4804
KEYCLOAK-4804 : Added a new container bundle module for Spring Boot
2017-04-27 10:16:49 +02:00
sebastienblanc 0781f3b33d add shading
add new module containing adapters

remove conditional bean

move bundle module
2017-04-27 09:15:36 +02:00
Pavel Drozd b683e43ea7 Merge pull request #4059 from vramik/KEYCLOAK-4776
KEYCLOAK-4776 include newly created tests to travis
2017-04-27 08:08:17 +02:00
Pavel Drozd 51e4beccf4 Merge pull request #4076 from vramik/KEYCLOAK-4732
KEYCLOAK-4732 fix for wildfly
2017-04-27 08:06:55 +02:00
Bill Burke 2b84b8255e Update host-slave.xml 2017-04-26 18:57:31 -04:00
Pedro Igor 0cad34abbe Merge pull request #4087 from pedroigor/master
Checking realm role directly
2017-04-26 16:51:14 -03:00
Pedro Igor 389e2b42f1 Test for uma_authorization scope 2017-04-26 16:04:37 -03:00
Pedro Igor 4e43518b2a Checking realm role directly 2017-04-26 15:39:37 -03:00
Stian Thorgersen cc27dd485b Merge pull request #4083 from knutz3n/KEYCLOAK-4780
KEYCLOAK-4780 Ensure Base64 encoded HMAC secret key is decoded before use
2017-04-26 20:19:33 +02:00
Pedro Igor b78cc63f0d Merge pull request #4084 from pedroigor/KEYCLOAK-4755
[KEYCLOAK-4755] - Client UI Tests
2017-04-26 13:29:00 -03:00
Pedro Igor b84507507d Merge pull request #4079 from mhajas/KEYCLOAK-4769
KEYCLOAK-4769 Add test for URI priority
2017-04-26 12:20:53 -03:00
Pedro Igor fbcfcfa088 [KEYCLOAK-4755] - Client UI Tests 2017-04-26 12:11:53 -03:00
Johannes Knutsen 0809033924 KEYCLOAK-4780 Ensure Base64 encoded HMAC secret key is decoded before use 2017-04-26 16:04:44 +02:00
Stian Thorgersen d6a0c9e186 Merge pull request #4082 from stianst/KEYCLOAK-4713
KEYCLOAK-4713 Update domain mode config for EAP 7.1
2017-04-26 15:59:02 +02:00
Stian Thorgersen 7c2ea4db98 Merge pull request #4080 from hmlnarik/KEYCLOAK-2122-Config-of-AssertionConsumerServiceUrl-in-Saml-Adapter
KEYCLOAK-2122 Configuration of AssertionConsumerServiceUrl in SAML adapter
2017-04-26 15:26:50 +02:00
Stian Thorgersen 4b417c5ae8 KEYCLOAK-4713 Update domain mode config for EAP 7.1 2017-04-26 15:17:43 +02:00
Stian Thorgersen 2913ee8e23 Merge pull request #4081 from stianst/KEYCLOAK-4785
KEYCLOAK-4785 Use realm name when creating admin console base url
2017-04-26 13:12:31 +02:00
Stian Thorgersen eedb40bbe0 Merge pull request #4071 from stianst/KEYCLOAK-4784
KEYCLOAK-4784 Cannot build project with -Dproduct
2017-04-26 12:51:20 +02:00
Stian Thorgersen f68b28db20 KEYCLOAK-4785 Use realm name when creating admin console base url 2017-04-26 12:39:56 +02:00
Stian Thorgersen c83e192a6f KEYCLOAK-4784 Add Jetty 9.3 to product profile 2017-04-26 12:07:47 +02:00
Hynek Mlnarik d7615d6a68 KEYCLOAK-2122 Configuration of AssertionConsumerServiceUrl in SAML adapter 2017-04-26 11:59:37 +02:00
mhajas 9c0e7cb4a5 KEYCLOAK-4769 Add test for URI priority 2017-04-26 08:32:40 +02:00
Pavel Drozd f1f2040910 Merge pull request #4000 from mhajas/KEYCLOAK-4703
KEYCLOAK-4703 Use phantomJS in adapter tests
2017-04-26 08:04:41 +02:00
Pedro Igor 0ccb98a81f Merge pull request #4078 from pedroigor/KEYCLOAK-3135
[KEYCLOAK-3135] - Rules UI Tests
2017-04-25 18:04:09 -03:00
Pedro Igor 5b5cfb01b9 Merge pull request #4077 from pedroigor/KEYCLOAK-4792
[KEYCLOAK-4792] - Client credentials provider support and making easier to obtain authz client
2017-04-25 18:03:32 -03:00
Pedro Igor b3131bf679 [KEYCLOAK-3135] - Rules UI Tests 2017-04-25 16:52:14 -03:00
Pedro Igor 79c9078caa [KEYCLOAK-4792] - Client credentials provider support and making easier to obtain authz client 2017-04-25 14:51:45 -03:00
Pedro Igor 4b01c8e4dc Merge pull request #4075 from pedroigor/KEYCLOAK-4732
[KEYCLOAK-4732] - Need to run the test using the target testing realm
2017-04-25 13:38:50 -03:00
vramik a3c57f4326 KEYCLOAK-4732 fix for wildfly 2017-04-25 13:57:14 +02:00
Pedro Igor ab58779d22 [KEYCLOAK-4732] - Need to run the test using the target testing realm 2017-04-25 08:34:39 -03:00
Pedro Igor 38ae6c981b Merge pull request #4068 from pedroigor/KEYCLOAK-3135
[KEYCLOAK-3135] - Scope permission UI tests and reusable ui-select2 component
2017-04-25 08:19:32 -03:00
Marek Posolda e678a0362b Merge pull request #4073 from mposolda/master
KEYCLOAK-4789 Can't remove userStorage when linked users have consent
2017-04-25 12:23:03 +02:00
mposolda 8000baeb1f KEYCLOAK-4789 Can't remove userStorage when linked users have consent 2017-04-25 11:32:26 +02:00
Stian Thorgersen cf7f28d97e Merge pull request #4031 from abacusresearch/KEYCLOAK-4736_http_header_x-xss-protection
KEYCLOAK-4736 Extend security defenses with X-XSS-Protection header
2017-04-25 10:38:21 +02:00
Stian Thorgersen 84f5df4814 Merge pull request #4070 from stianst/KEYCLOAK-4671
KEYCLOAK-4671 Add server-private-spi to dependency deployer
2017-04-25 10:36:22 +02:00
Stian Thorgersen d081f967ea Merge pull request #4067 from hmlnarik/KEYCLOAK-4779
KEYCLOAK-4779 Fix NPE
2017-04-25 10:31:00 +02:00
Stian Thorgersen 54ee055bd8 KEYCLOAK-4671 Add server-private-spi to dependency deployer 2017-04-25 10:16:24 +02:00
Marek Posolda e48340121b Merge pull request #4069 from mposolda/master
KEYCLOAK-4271 Migration test for offline tokens - manual mode
2017-04-25 10:10:19 +02:00
mposolda b81891f89b KEYCLOAK-4271 Migration test for offline tokens - manual mode 2017-04-25 09:18:33 +02:00
Stian Thorgersen 1385d3c219 Merge pull request #4062 from ssilvert/dbl-click
KEYCLOAK-4121: Prevent double form submission
2017-04-25 08:57:15 +02:00
Pedro Igor 49547ccfbc [KEYCLOAK-3135] - Scope permission UI tests and reusable ui-select2 component 2017-04-24 23:12:46 -03:00
Hynek Mlnarik e8a65017fa KEYCLOAK-4779 Fix NPE 2017-04-24 23:09:27 +02:00
Pedro Igor 5e57e84384 Merge pull request #4054 from pedroigor/KEYCLOAK-3135
[KEYCLOAK-3135] - More changes to Policy Management API
2017-04-24 17:44:07 -03:00
Pedro Igor 5972c94dc8 [KEYCLOAK-3135] - More UI tests 2017-04-24 16:50:23 -03:00
Marek Posolda c40d79afb0 Merge pull request #4065 from mposolda/master
KEYCLOAK-4326 KEYCLOAK-4588 Can't get granted consents if client temp…
2017-04-24 16:38:20 +02:00
mposolda d05a894831 KEYCLOAK-4326 KEYCLOAK-4588 Can't get granted consents if client template mappers were consented to 2017-04-24 15:44:38 +02:00
Pedro Igor dfec691de0 [KEYCLOAK-3135] - Fixing cancel button 2017-04-24 08:39:08 -03:00
Marek Posolda 03e6c0884a Merge pull request #4063 from mposolda/master
KEYCLOAK-4525 Deleting a client with existing sessions/offline_tokens…
2017-04-24 13:37:36 +02:00
Pedro Igor e0f753bcf5 [KEYCLOAK-3135] - More changes to Policy Management API 2017-04-24 07:34:08 -03:00
mposolda 1fd5af840b KEYCLOAK-4525 Deleting a client with existing sessions/offline_tokens leads to Internal Server Errors 2017-04-24 11:24:09 +02:00
Stan Silvert 8dc65cff0a KEYCLOAK-4121: Prevent double form submission 2017-04-21 14:11:44 -04:00
Stian Thorgersen 3dbd0d5063 Merge pull request #3838 from ahus1/KEYCLOAK-4208-spring-boot-adapter-roles
KEYCLOAK-4208 restructure spring auth config to match servlet spec
2017-04-21 15:34:09 +02:00
Stian Thorgersen 6c09df0cae Merge pull request #4058 from stianst/KEYCLOAK-4503
KEYCLOAK-4503 Require init with token and refreshToken
2017-04-21 15:19:09 +02:00
Stian Thorgersen 09bc16e6c5 Merge pull request #4060 from stianst/KEYCLOAK-4774
KEYCLOAK-4774 redirect_fragment doesn't work in Admin Console
2017-04-21 15:18:40 +02:00
Stian Thorgersen f92ad70ff0 KEYCLOAK-4774 redirect_fragment doesn't work in Admin Console 2017-04-21 14:03:05 +02:00
vramik 15f1b948bf KEYCLOAK-4776 include newly created tests to travis 2017-04-21 14:00:42 +02:00
Pavel Drozd 95fc8f79dd Merge pull request #4051 from mhajas/KEYCLOAK-4505
KEYCLOAK-4505 Add test of clientSession for script based authenticator
2017-04-21 13:50:29 +02:00
Pavel Drozd f50e08d111 Merge pull request #4044 from vmuzikar/adapter-compat-upstream
KEYCLOAK-4761 Support for Java adapter backward compatibility testing
2017-04-21 13:49:17 +02:00
Stian Thorgersen 257a973995 KEYCLOAK-4503 Require init with token and refreshToken 2017-04-21 13:39:53 +02:00
Stian Thorgersen 606c385f26 Merge pull request #4057 from stianst/KEYCLOAK-4480
KEYCLOAK-4480 Fix re-encoding of query params in keycloak.js after re…
2017-04-21 13:37:44 +02:00
Stian Thorgersen e6486ab1c1 KEYCLOAK-4480 Fix re-encoding of query params in keycloak.js after redirect 2017-04-21 13:29:46 +02:00
Stian Thorgersen b45089f5f0 Merge pull request #4033 from sebastienblanc/KEYCLOAK-3818
KEYCLOAK-3818 : safer method to retrieve the webcontext for jetty
2017-04-21 11:20:59 +02:00
Stian Thorgersen e85d8774da Merge pull request #4055 from ssilvert/regex-trunc
KEYCLOAK-4402: Fix regexp password policy.
2017-04-21 09:46:00 +02:00
Stan Silvert 62000e042d KEYCLOAK-4402: Fix regexp password policy. 2017-04-20 18:09:20 -04:00
Pedro Igor fa1b998802 Merge pull request #4050 from pedroigor/KEYCLOAK-4769
[KEYCLOAK-4769] - Policy enforcer path matching tests
2017-04-20 14:02:59 -03:00
Pedro Igor df163d86e8 Merge pull request #4052 from pedroigor/KEYCLOAK-4754
[KEYCLOAK-4754] - Unable to delete realm when using aggregated policies
2017-04-20 13:23:09 -03:00
Pedro Igor 70a3dd1e4a [KEYCLOAK-4769] - Better error message when resource has no or invalid uri 2017-04-20 13:21:01 -03:00
Pedro Igor 80a80512ea [KEYCLOAK-4769] - Policy enforcer path matching tests 2017-04-20 13:21:01 -03:00
mhajas 4f66919474 KEYCLOAK-4505 Add tests of clientSession for script based authenticator 2017-04-20 17:10:56 +02:00
Pedro Igor bf69bc94bb [KEYCLOAK-4754] - Unable to delete realm when using aggregated policies 2017-04-20 12:10:52 -03:00
Pavel Drozd 585653b88e Merge pull request #4038 from vmuzikar/social-fix
KEYCLOAK-4624 Fix, stabilize and revamp SocialLoginTest
2017-04-20 13:13:29 +02:00
Alexander Schwartz 4d5fd0b75e KEYCLOAK-4208 restructure spring config to match servlet spec. updating jetty, tomcat and undertow 2017-04-20 12:52:13 +02:00
Stian Thorgersen 2a8b2aabb9 Merge pull request #4049 from stianst/KEYCLOAK-4738
KEYCLOAK-4738 Make sure script engine always uses correct classloader
2017-04-20 10:02:23 +02:00
Stian Thorgersen 1d03eb5f2b Merge pull request #4045 from stianst/KEYCLOAK-4737
KEYCLOAK-4737 Admin Console redirect loop when hostname contains console
2017-04-20 09:29:41 +02:00
Stian Thorgersen 4da07474fa KEYCLOAK-4738 Make sure script engine always uses correct classloader 2017-04-20 09:28:46 +02:00
Stian Thorgersen 14b109da18 Merge pull request #4047 from stianst/KEYCLOAK-4287
KEYCLOAK-4287 Remove deprecated session iframe endpoint
2017-04-19 15:49:40 +02:00
Stian Thorgersen 7de0b329a2 Merge pull request #4046 from stianst/KEYCLOAK-4637
KEYCLOAK-4637 Fix FreeOTP url in Swedish translation
2017-04-19 15:48:12 +02:00
Stian Thorgersen 81123e0eea Merge pull request #4041 from mlindstr/KEYCLOAK-4762
KEYCLOAK-4762 Improve French translations
2017-04-19 15:46:52 +02:00
Stian Thorgersen 8919015f74 KEYCLOAK-4287 Remove deprecated session iframe endpoint 2017-04-19 15:01:15 +02:00
Stian Thorgersen b72166ebf1 Merge pull request #4043 from stianst/KEYCLOAK-4764
KEYCLOAK-4764 Fixes for distribution
2017-04-19 14:55:26 +02:00
Stian Thorgersen 10009868a3 KEYCLOAK-4637 Fix FreeOTP url in Swedish translation 2017-04-19 14:54:44 +02:00
Stian Thorgersen 0a0d2174e4 KEYCLOAK-4737 Admin Console redirect loop when hostname contains console 2017-04-19 14:43:56 +02:00
Stian Thorgersen 038c4765a3 KEYCLOAK-4764 Fixes for distribution 2017-04-19 13:58:39 +02:00
Vaclav Muzikar c7a97cfd21 KEYCLOAK-4761 Prepare the testsuite for Java adapter backward compatibility testing 2017-04-19 13:51:24 +02:00
Markus Lindström 0b21ed3e0e KEYCLOAK-4762 Improve French translations 2017-04-19 10:23:52 +02:00
Stian Thorgersen 906739f8f3 Merge pull request #4034 from sebastienblanc/KEYCLOAK-3108
KEYCLOAK-3108: Make the credentials map case insensitive
2017-04-19 09:49:07 +02:00
Stian Thorgersen c9630157e8 Merge pull request #4035 from sebastienblanc/KEYCLOAK-4486
KEYCLOAK-4486: add autodetect-bearer-only attribute in subsystem
2017-04-19 09:47:42 +02:00
Stian Thorgersen 51eef9b8b3 Merge pull request #4037 from Nicologies/master
Remove the deprecated from readString(InputStream, Charset)
2017-04-19 09:46:44 +02:00
Stian Thorgersen 330663dfd3 Merge pull request #3898 from chameleon82/KEYCLOAK-4502_Update_Russian_Translation
KEYCLOAK-4502 Update Russian translation
2017-04-19 09:41:49 +02:00
Stian Thorgersen e54c1d7de1 Merge pull request #4026 from mhajas/KEYCLOAK-4733
KEYCLOAK-4733 Replace character 160 with character 32
2017-04-18 15:21:23 +02:00
Stian Thorgersen da6781dd91 Merge pull request #4029 from abacusresearch/KEYCLOAK-4734_update_italian_translation
KEYCLOAK-4734 Update Italian translations
2017-04-18 15:14:33 +02:00
Stian Thorgersen 4f771ac51a Merge pull request #4027 from abacusresearch/KEYCLOAK-4729_update_german_translation
KEYCLOAK-4729 Update German translations
2017-04-18 15:13:39 +02:00
Pedro Igor 5ccf412fe2 Merge pull request #4039 from pedroigor/master
[KEYCLOAK-4755] - AuthZ UI Tests
2017-04-13 18:31:02 -03:00
Pedro Igor ac6eb79b53 [KEYCLOAK-4755] - Changing javadoc and license 2017-04-13 15:59:02 -03:00
Pedro Igor a415ea3670 [KEYCLOAK-4755] - AuthZ UI Tests 2017-04-13 15:54:52 -03:00
Vaclav Muzikar 32b62b2a70 KEYCLOAK-4624 Fix, stabilize and revamp SocialLoginTest 2017-04-13 13:41:30 +02:00
Pedro Igor 4344ceefc2 Merge pull request #4036 from pedroigor/master
[KEYCLOAK-4751] - Send default access denied page when requests don't match any path config
2017-04-13 08:16:32 -03:00
EbenZhang fa97c2419e Remove the deprecated from readString(InputStream, Charset)
I believe it was copied from the previous overload.
2017-04-13 15:42:23 +08:00
Pedro Igor 964693077a [KEYCLOAK-4751] - More tests 2017-04-12 18:25:38 -03:00
Pedro Igor 2a1a19f290 [KEYCLOAK-4751] - Send default access denied page when requests don't match any path config 2017-04-12 18:25:13 -03:00
Pedro Igor 2336e97bf0 Merge pull request #4030 from pedroigor/KEYCLOAK-3135
[KEYCLOAK-3135] - Part 1: Permission Management API
2017-04-12 16:02:58 -03:00
Pedro Igor b6978a424f [KEYCLOAK-3135] - Reverting change to support import unordered policies 2017-04-12 15:15:46 -03:00
Pedro Igor 8e877a7f6c [KEYCLOAK-3135] - More tests 2017-04-12 14:34:27 -03:00
sebastienblanc 886528dab8 add autodetect-bearer-only in subsystem 2017-04-12 16:40:19 +02:00
sebastienblanc 9a2d36aa9d KEYCLOAK-3108: Make the credentials map case insensitive 2017-04-12 10:58:54 +02:00
sebastienblanc ea9c663ae1 try the registered beans , then the handler 2017-04-12 10:41:46 +02:00
Pedro Igor eec712a259 [KEYCLOAK-3135] - Role and user policies apis 2017-04-12 00:52:14 -03:00
Pedro Igor 54ebc1918c [KEYCLOAK-3135] - Using abstract policy representation when creating policies and updating tests 2017-04-12 00:52:13 -03:00
Pedro Igor d60dcb4c62 [KEYCLOAK-3135] - Some more tests and making policy type rest api more generic 2017-04-12 00:52:13 -03:00
Pedro Igor 8e64bc3e4d Tests for new permission management rest api 2017-04-12 00:52:13 -03:00
Pedro Igor cf1e8d1dd8 [KEYCLOAK-3135] - Tests and typos 2017-04-12 00:52:13 -03:00
Pedro Igor 0b8fc3d6e1 [KEYCLOAK-3135] - Fixing permission test 2017-04-12 00:52:13 -03:00
Pedro Igor 55f747ecd0 [KEYCLOAK-3135] - Part 1: Permission Management API 2017-04-12 00:52:13 -03:00
sebastienblanc a011f44d39 safer method to retrieve the webcontext for jetty 2017-04-11 18:53:58 +02:00
Marek Posolda 00b832b1cd Merge pull request #4003 from abstractj/refactor-test-helper
Inclusion of support for credentials
2017-04-10 21:00:41 +02:00
Dominik Langenegger 8840bc073f KEYCLOAK-4736 Extend security defenses with additional option to set the X-XSS-Protection header, block by default 2017-04-10 11:20:07 +02:00
Pavel Drozd bfd76d7813 Merge pull request #3962 from mhajas/KEYCLOAK-4366
KEYCLOAK-4366
2017-04-10 08:44:52 +02:00
Nekrasov Aleksander 2066259518 KEYCLOAK-4502 Update Russian translation 2017-04-08 11:42:33 +07:00
Nekrasov Aleksander 9bca7fb7c5 KEYCLOAK-4502 Update russian translation 2017-04-08 11:27:34 +07:00
Bill Burke cf095766c7 Merge pull request #4028 from mtrue01/pullmyothercodefinger
[KEYCLOAK-3964] NoImport Add coverage for basic test behavior
2017-04-07 12:26:10 -04:00
Dominik Langenegger c73de4f2b9 KEYCLOAK-4734 Update Italian translations 2017-04-07 16:46:43 +02:00
Mark True 4daafa56fc [KEYCLOAK-3964] NoImport Add coverage for basic test behavior 2017-04-07 10:37:02 -04:00
Dominik Langenegger 16430791bb KEYCLOAK-4729 Update German translations 2017-04-07 16:03:34 +02:00
Pavel Drozd 5e2446f838 Merge pull request #4025 from mtrue01/pullmycodefinger
KEYCLOAK-4533 Add test for remove user from ldap
2017-04-07 16:00:37 +02:00
Pavel Drozd b18c8c92c5 Merge pull request #4007 from mhajas/KEYCLOAK-4288
KEYCLOAK-4288 Run tests on EAP7
2017-04-07 15:35:12 +02:00
mhajas e8bbfd9012 KEYCLOAK-4733 Replace character 160 with character 32 2017-04-07 15:30:54 +02:00
Mark True 94d375886f Keycloak 4533 commit 2017-04-07 09:26:22 -04:00
Bruno Oliveira f9c017efaf Inclusion of support for credentials
- Added support for credentials
- Less verbose methods
2017-04-07 06:05:24 -03:00
Stian Thorgersen 0db2640076 Merge pull request #4023 from abacusresearch/KEYCLOAK-4728_update_french_translation
KEYCLOAK-4728 Fix typo
2017-04-07 09:45:18 +02:00
Stian Thorgersen ebabc6fd8a Merge pull request #3936 from glavoie/KEYCLOAK-4563
KEYCLOAK-4563: Large user account ID and group ID may break distribut…
2017-04-07 09:37:29 +02:00
Stian Thorgersen 56320cc023 Merge branch 'master' into KEYCLOAK-4563 2017-04-07 09:36:40 +02:00
Dominik Langenegger e9d22f3506 KEYCLOAK-4728 Fix typo 2017-04-07 09:31:05 +02:00
Stian Thorgersen 83d0f313ce Merge pull request #4011 from mstruk/KEYCLOAK-4719
KEYCLOAK-4719 CLI tests fail when run from within the IDE
2017-04-07 09:17:19 +02:00
Bill Burke cac19c8a8f Merge pull request #4021 from patriot1burke/master
fix protocol mappers
2017-04-06 18:34:33 -04:00
Bill Burke 9452d37926 Merge remote-tracking branch 'upstream/master' 2017-04-06 18:33:50 -04:00
Bill Burke 2e284bdd9b fix protocol mappers 2017-04-06 18:33:06 -04:00
Bill Burke 22dc6ffcf3 Merge pull request #4020 from keycloak/revert-4019-master
Revert "KEYCLOAK-4727 KEYCLOAK-4652 - Fixing protocol mappers when evaluating policies using the tool"
2017-04-06 18:25:02 -04:00
Bill Burke 54cd41c955 Revert "KEYCLOAK-4727 KEYCLOAK-4652 - Fixing protocol mappers when evaluating policies using the tool" 2017-04-06 18:24:31 -04:00
Pedro Igor 7cf8bd2dcf Merge pull request #4019 from pedroigor/master
KEYCLOAK-4727 KEYCLOAK-4652 - Fixing protocol mappers when evaluating policies using the tool
2017-04-06 19:20:14 -03:00
Pedro Igor 6a959b32fc KEYCLOAK-4727 KEYCLOAK-4652 - Fixing protocol mappers when evaluating policies using the tool 2017-04-06 18:43:54 -03:00
Bill Burke 3ce0c57e17 Merge pull request #3831 from Hitachi/master
KEYCLOAK-2604 Proof Key for Code Exchange by OAuth Public Clients
2017-04-06 15:36:08 -04:00
Bill Burke 0fd11d16ee Merge pull request #3983 from bartoszmajsak/oso_typo_fix
Fixes misspelled config class in Openshift provider
2017-04-06 15:29:44 -04:00
Bill Burke 6ca5b7de03 Merge pull request #3998 from cainj13/fixNullProtocols
Fix null protocols for default clients
2017-04-06 15:29:21 -04:00
Bill Burke c198f4ffa7 Merge pull request #4015 from patriot1burke/master
KEYCLOAK-4727 KEYCLOAK-4652
2017-04-06 15:27:49 -04:00
Bill Burke 665bcab7b7 Merge remote-tracking branch 'upstream/master' 2017-04-06 15:10:31 -04:00
Bill Burke 13afc0147e close user/client session later 2017-04-06 15:07:40 -04:00
Bill Burke 26db0dd1fc Merge pull request #4016 from pedroigor/KEYCLOAK-4726
[KEYCLOAK-4726] - Multiple role policies crash realm delete
2017-04-06 13:21:53 -04:00
Pedro Igor 1f50421a54 [KEYCLOAK-4726] - Multiple role policies crash realm delete 2017-04-06 12:36:03 -03:00
Bill Burke 1b3549f828 oops 2017-04-06 10:49:48 -04:00
Bill Burke d635e7aadd oops 2017-04-06 10:48:23 -04:00
Bill Burke 201d2c6aac Merge remote-tracking branch 'upstream/master' 2017-04-06 10:44:43 -04:00
Bill Burke 31074c3c8d KEYCLOAK-4727 KEYCLOAK-4652 2017-04-06 10:44:33 -04:00
Stian Thorgersen 2876a98a97 Merge pull request #4013 from stianst/KEYCLOAK-4702
KEYCLOAK-4702 Use service dependency on jndi entry for caches
2017-04-06 15:44:21 +02:00
Stian Thorgersen af4c74f1d9 Merge pull request #3718 from thomasdarimont/issue/KEYCLOAK-4163-improve-support-for-email-addresses
KEYCLOAK-4163 Improve support for e-mail addresses
2017-04-06 15:34:30 +02:00
Stian Thorgersen e622ea1eba KEYCLOAK-4702 Use service dependency on jndi entry for caches 2017-04-06 15:06:45 +02:00
Marko Strukelj 0269db0e85 KEYCLOAK-4719 CLI tests fail when run from within the IDE 2017-04-06 12:46:05 +02:00
Stian Thorgersen 859b575a12 Merge pull request #4009 from stianst/master
KEYCLOAK-4717 Added extra check for data content in receive message f…
2017-04-06 10:42:37 +02:00
Stian Thorgersen f0b44ea93b KEYCLOAK-4717 Added extra check for data content in receive message for session iframe 2017-04-06 08:49:32 +02:00
Stian Thorgersen 802f648757 Merge pull request #4006 from diego0020/patch-1
Verify message comes from loginIframe
2017-04-06 08:34:38 +02:00
Stian Thorgersen b834f6ebf9 Merge pull request #4008 from stianst/KEYCLOAK-4697
KEYCLOAK-4549 [RH-SSO] EAP 7.1.0 Alpha16
2017-04-05 14:55:44 +02:00
Stian Thorgersen 6201257f76 KEYCLOAK-4549 [RH-SSO] EAP 7.1.0 Alpha16 2017-04-05 11:55:21 +02:00
mhajas 670103356f KEYCLOAK-4288 Run tests on EAP7 2017-04-05 10:28:04 +02:00
diego0020 a82278dcbf Verify message comes from loginIframe
In the current implementation a message coming from any window on the same origin may cause the refresh token to be cleared.
In my case, messages generated by a chrome extension were causing the application to logout unexpectedly. With additional condition only messages coming from the login iFrame will be processed. Another suggestion would be changing the condition `event.data != "unchanged"` to something more specific.
2017-04-04 16:32:21 -05:00
Stian Thorgersen 4845286e04 Merge pull request #4001 from stianst/KEYCLOAK-4693
KEYCLOAK-4693
2017-04-04 15:48:08 +02:00
Marek Posolda ad1ca78034 Merge pull request #4002 from mposolda/master
KEYCLOAK-4705 Running test from IDE should log INFO to the console
2017-04-04 11:52:10 +02:00
Pavel Drozd 30b785c60d Merge pull request #3999 from vmuzikar/ie-fix
KEYCLOAK-4351 Stabilize TermsAndConditions test in IE
2017-04-04 10:48:22 +02:00
Pavel Drozd b4c5eb8354 Merge pull request #3994 from vramik/KEYCLOAK-4534
KEYCLOAK-4534 ClientInitiatedAccountLinkTest fails with auth-server-w…
2017-04-04 10:47:36 +02:00
Pavel Drozd 91c3977d71 Merge pull request #3988 from mhajas/KEYCLOAK-3955
KEYCLOAK-3955
2017-04-04 10:46:12 +02:00
Pavel Drozd bb0b3c6470 Merge pull request #3987 from mhajas/KEYCLOAK-3696
KEYCLOAK-3696 Fix SPFacade servlet
2017-04-04 10:45:47 +02:00
Pavel Drozd 8036f12114 Merge pull request #3986 from mhajas/KEYCLOAK-4677
KEYCLOAK-4677 Fix javascript adapter tests
2017-04-04 10:45:07 +02:00
mposolda 457f183d46 KEYCLOAK-4705 Running test from IDE should log INFO to the console 2017-04-04 10:15:22 +02:00
Stian Thorgersen eaf386f1d2 KEYCLOAK-4693
Improve blocking search indexing
2017-04-04 09:56:48 +02:00
mhajas 04182d1d44 KEYCLOAK-4703 Use phantomJS in adapter tests 2017-04-04 09:17:00 +02:00
Vaclav Muzikar 5e360cf919 KEYCLOAK-4351 Stabilize TermsAndConditions test in IE 2017-04-04 07:40:16 +02:00
Pedro Igor f371a00e98 Merge pull request #3997 from pedroigor/KEYCLOAK-3573
[KEYCLOAK-3573] - Elytron adapter CLI scripts and tests
2017-04-03 09:22:29 -03:00
Stian Thorgersen e9f9f90b35 Merge pull request #3996 from abstractj/refactor-test-helper
Removal of duplicated code for testhelper
2017-04-03 08:30:11 +02:00
Josh Cain 971f053f13 flip null switch for conditionally adding login protocol to default clients 2017-03-31 16:20:21 -05:00
Josh Cain 0482ec40fd Fix null protocols in default realm applications 2017-03-31 16:13:38 -05:00
Pedro Igor f857625d07 [KEYCLOAK-3573] - Elytron adapter CLI scripts and tests. 2017-03-31 11:31:33 -03:00
Bruno Oliveira 01e7d79b1f Removal of duplicated code for testhelper
Effectively make use of username and password
Refactoring packages
Including ClientBuilder
2017-03-31 10:34:59 -03:00
Stian Thorgersen d264a823d9 Merge pull request #3993 from sebastienblanc/extract_initialtoken_generator
KEYCLOAK-4691: Extract iat generator to method
2017-03-31 13:13:26 +02:00
Pedro Igor bfaaf2b8fa Merge pull request #3992 from pedroigor/KEYCLOAK-4650
[KEYCLOAK-4650] - Confirmation dialog when disabling authorization settings
2017-03-31 07:44:10 -03:00
vramik ca6d8c9dbe KEYCLOAK-4534 ClientInitiatedAccountLinkTest fails with auth-server-wildlfy 2017-03-30 12:47:51 +02:00
sebastienblanc 0e8337ba8e KEYCLOAK-4691: Extract iat generator to method 2017-03-30 10:51:28 +02:00
Pedro Igor 838a045239 [KEYCLOAK-4650] - Adding scope filter and fixing cancel buttons 2017-03-29 12:59:41 -03:00
Pedro Igor 33a0dc880f [KEYCLOAK-4650] - Confirmation dialog when disabling authorization settings 2017-03-29 11:17:10 -03:00
Stian Thorgersen 2d40c8d8c2 Merge pull request #3991 from stianst/KEYCLOAK-4615
KEYCLOAK-4615 Build demo-dist, example-dist and proxy-dist only in jb…
2017-03-29 13:38:06 +02:00
Pedro Igor 5d573b1b3e [KEYCLOAK-3573] - Removing unnecessary elytron directory 2017-03-29 08:36:05 -03:00
Stian Thorgersen 642aeeb937 KEYCLOAK-4615 Build demo-dist, example-dist and proxy-dist only in jboss-release profile 2017-03-29 11:39:40 +02:00
Stian Thorgersen e8e1cce14a Merge pull request #3985 from stianst/KEYCLOAK-3250-PROD-PROFILE
KEYCLOAK-4668 Exclude modules in product profile
2017-03-29 09:57:35 +02:00
Stian Thorgersen 6c8b207bf5 Merge pull request #3989 from mstruk/KEYCLOAK-4496
KEYCLOAK-4496 Strange truncation of Client information when creating a new client
2017-03-29 08:25:00 +02:00
Takashi Norimatsu a183d50ad2 delete erroneous characters inserted by mistake 2017-03-29 09:53:24 +09:00
Marko Strukelj d26f2b44bd KEYCLOAK-4496 Strange truncation of Client information when creating a new client
- Added polyfill from https://github.com/tbosch/autofill-event
2017-03-28 18:06:17 +02:00
mhajas 3bb587530b KEYCLOAK-3955 2017-03-28 16:05:44 +02:00
mhajas 438ec8d245 Fix SPFacade servlet 2017-03-28 15:12:33 +02:00
mhajas bc05010ece Fix javascript adapter tests 2017-03-28 15:02:44 +02:00
Stian Thorgersen 0180d54dd9 KEYCLOAK-4668 Exclude modules in product profile 2017-03-28 10:04:20 +02:00
Pavel Drozd 45ea3c8b47 Merge pull request #3977 from vmuzikar/KEYCLOAK-4613
KEYCLOAK-4613 Fix Console UI and Social Login tests
2017-03-28 09:34:23 +02:00
Takashi Norimatsu ef3aef9381 Merge branch 'master' into master 2017-03-28 16:21:40 +09:00
Stian Thorgersen 93c51c5aad Merge pull request #3984 from stianst/KEYCLOAK-3250-PROD-PROFILE
KEYCLOAK-3258 Add server dist changes to product profile
2017-03-28 08:55:57 +02:00
Stian Thorgersen 6b21b4d87b KEYCLOAK-4657 Sort out REST API for prod profile 2017-03-27 20:50:13 +02:00
Stian Thorgersen 9303a9c7d0 KEYCLOAK-3258 Add server dist changes to product profile 2017-03-27 20:50:13 +02:00
Vaclav Muzikar 66c13b4a72 KEYCLOAK-4613 Fix Console UI and Social Login tests 2017-03-27 15:25:24 +02:00
mhajas 36fc643bfb KEYCLOAK-4366 2017-03-27 11:22:01 +02:00
Bartosz Majsak 0197600565 Fixes misspelled config class 2017-03-27 09:38:47 +02:00
Pavel Drozd ed67dcc712 Merge pull request #3975 from vmuzikar/KEYCLOAK-4660
KEYCLOAK-4660 Add support for Chrome CLI switches to Arquillian Tests…
2017-03-27 09:38:33 +02:00
Pavel Drozd 4b813ea1d1 Merge pull request #3960 from mhajas/KEYCLOAK-3961
KEYCLOAK-3961 Fix wrong conflict merge
2017-03-27 09:37:18 +02:00
Pavel Drozd 4aa996c2db Merge pull request #3959 from mhajas/KEYCLOAK-4141
KEYCLOAK-4141 Added saml tests
2017-03-27 09:36:41 +02:00
Pavel Drozd b1535d4751 Merge pull request #3951 from vramik/KEYCLOAK-4571
KEYCLOAK-4571 Adapt server-config-migration module for testing both p…
2017-03-27 09:34:33 +02:00
Bill Burke 71f0c01d4f Merge pull request #3980 from patriot1burke/master
KEYCLOAK-4664 KEYCLOAK-4665
2017-03-25 20:12:22 -04:00
Bill Burke f554fd90db Merge pull request #3911 from almighty/oso_provider
[KEYCLOAK-4528] Adds Openshift Identity Provider as part of social brokers
2017-03-25 19:25:44 -04:00
Bill Burke e5a2642e62 Merge pull request #3978 from pedroigor/KEYCLOAK-3573
[KEYCLOAK-3573] - Elytron SAML and OIDC Adapters
2017-03-25 19:24:42 -04:00
Bill Burke 8c2e756732 fix 2017-03-25 19:21:50 -04:00
Bill Burke d8e98d1de6 KEYCLOAK-4665 2017-03-25 12:47:32 -04:00
Bill Burke dd8a64f30c KEYCLOAK-4664 2017-03-25 11:21:11 -04:00
Stian Thorgersen 3ce8da0126 Merge pull request #3976 from stianst/KEYCLOAK-3250-PROD-PROFILE
KEYCLOAK-4659 Changes to adapters for product profile
2017-03-24 15:34:35 +01:00
Pedro Igor 30d7a5b01f [KEYCLOAK-3573] - Elytron SAML and OIDC Adapters 2017-03-24 11:32:08 -03:00
Stian Thorgersen 7968394537 KEYCLOAK-4654 Disable unsupported LDAP vendors in product profile 2017-03-24 13:44:33 +01:00
Vaclav Muzikar 6a093abfdb KEYCLOAK-4660 Add support for Chrome CLI switches to Arquillian Testsuite 2017-03-24 12:25:49 +01:00
Nekrasov Aleksander d0b3cb32f0 KEYCLOAK-4502 Update Russian translation 2017-03-24 18:22:25 +07:00
Stian Thorgersen 5d028205bf KEYCLOAK-4659 Changes to adapters for product profile 2017-03-24 12:07:21 +01:00
Stian Thorgersen 0b2896458a Merge pull request #3974 from stianst/KEYCLOAK-3250-PROD-PROFILE
KEYCLOAK-4658 Updates client-cli
2017-03-24 11:19:56 +01:00
Stian Thorgersen e74f037732 KEYCLOAK-4658 Updates client-cli 2017-03-24 09:41:56 +01:00
Stian Thorgersen ef7cb1e0cb Merge pull request #3973 from stianst/KEYCLOAK-3250-PROD-PROFILE
KEYCLOAK-3251 Add product Maven profile
2017-03-24 09:36:28 +01:00
vramik 49e43e59c4 patch MigrationServerConfigTest 2017-03-24 09:31:53 +01:00
Pavel Drozd 996f60ff57 Merge pull request #3963 from Pepo48/KEYCLOAK-4488
KEYCLOAK-4488 Fix Auth Flows Console UI tests
2017-03-24 08:45:48 +01:00
Stian Thorgersen 90c4de27e5 KEYCLOAK-3251 Add product Maven profile
KEYCLOAK-3254 Product profile should include RH-SSO theme and change default theme
2017-03-24 07:10:11 +01:00
Bill Burke 815e9e8e02 Merge pull request #3968 from vramik/KEYCLOAK-4229
KEYCLOAK-4229 Add migration test from 2.5.5
2017-03-23 14:48:39 -04:00
Bill Burke d1e71acf10 Merge pull request #3961 from jblashka/maxLifespanInvalidationFixes
KEYCLOAK-4612 Fix CachePolicy.MAX_LIFESPAN invalidation
2017-03-23 14:25:21 -04:00
Stian Thorgersen fc009969c9 Merge pull request #3971 from ssilvert/KEYCLOAK-4396-ng2-wrapper
KEYCLOAK-4396: Add keycloak.d.ts for TypeScript
2017-03-23 14:12:03 +01:00
Bartosz Majsak 63e8e7f842 Alings SimpleHttp API with new version 2017-03-23 13:51:14 +01:00
Bartosz Majsak 210143738e Merge branch 'master' into oso_provider 2017-03-23 13:45:07 +01:00
Pedro Igor deae380941 Merge pull request #3964 from pedroigor/KEYCLOAK-4587
[KEYCLOAK-4587] - Missing breadcrumb
2017-03-22 13:55:50 -03:00
vramik 1fccff7e7c KEYCLOAK-4229 Add migration test from 2.5.5 2017-03-22 14:19:35 +01:00
Stian Thorgersen 275e871618 Merge pull request #3966 from vramik/KEYCLOAK-4638
KEYCLOAK-4638 Migrator to 3.0.0 contains code coppied from 2.5.0
2017-03-22 13:43:23 +01:00
vramik c41bc65bf8 KEYCLOAK-4638 Migrator to 3.0.0 contains code coppied from 2.5.0 2017-03-22 13:08:12 +01:00
Marek Posolda 975dfe9489 Merge pull request #3167 from brat000012001/master
X509 Certificate user authentication
2017-03-22 08:26:26 +01:00
Stian Thorgersen 5cf6438a45 Merge pull request #3965 from thomasdarimont/issue/KEYCLOAK-4614-fix-linkonly-tooltip-reference
KEYCLOAK-4614 Fix linkOnly tooltip reference
2017-03-22 08:18:29 +01:00
Thomas Darimont 05a8fffdbf KEYCLOAK-4614 Fix linkOnly tooltip reference 2017-03-22 00:07:40 +01:00
Pedro Igor c517565cc5 [KEYCLOAK-4587] - Missing breadcrumb 2017-03-21 16:55:21 -03:00
Peter Zaoral 0a8ca19944 KEYCLOAK-4488 Fix Auth Flows Console UI tests
Signed-off-by: Peter Zaoral <pzaoral@redhat.com>
2017-03-21 11:16:08 +01:00
mhajas 7c1eb5582a KEYCLOAK-4141 Added saml tests 2017-03-21 10:41:06 +01:00
Jared Blashka 61bd9bb58c Fix CachePolicy.MAX_LIFESPAN invalidation 2017-03-20 22:56:35 -04:00
Stan Silvert e2970fcf8a KEYCLOAK-4396: Add keycloak.d.ts for TypeScript 2017-03-20 12:42:26 -04:00
mhajas 8b8b5174eb KEYCLOAK-3961 Fix wrong conflict merge 2017-03-20 15:04:32 +01:00
Pedro Igor b30b96b9a1 Merge pull request #3956 from pedroigor/KEYCLOAK-4602
Improve path matcher when using handling patterns and caching
2017-03-17 16:15:56 -03:00
Stian Thorgersen dce2b1dfde Merge pull request #3955 from vramik/KEYCLOAK-4601
KEYCLOAK-4601 Add nexus-staging-maven-plugin fo keycloak-bom-parent
2017-03-17 13:49:31 +01:00
Pedro Igor 258af94889 Delegating caching of resource instances to to path matcher 2017-03-17 09:35:19 -03:00
Pedro Igor dabd7c0b27 [KEYCLOAK-4602] - Improving pattern matching algorithm 2017-03-17 09:34:52 -03:00
Pedro Igor f6786e29c6 [KEYCLOAK-4602] - A runtime cache for path configurations 2017-03-17 09:34:16 -03:00
vramik eb852265ef KEYCLOAK-4601 Add nexus-staging-maven-plugin fo keycloak-bom-parent 2017-03-17 13:11:59 +01:00
Peter Nalyvayko b2f10359c8 KEYCLOAK-4335: x509 client certificate authentication
Started on implementing cert thumbprint validation as a part of x509 auth flow. Added a prompt screen to give users a choice to either log in based on the identity extracted from X509 cert or to continue with normal browser login flow authentication; clean up some of the comments

x509 authentication for browser and direct grant flows. Implemented certificate to user mapping based on user attribute

Implemented CRL and OCSP certificate revocation checking and added corresponding configuration settings to set up responderURI (OCSP), a location of a file containing X509CRL entries and switiches to enable/disable revocation checking; reworked the certificate validation; removed superflous logging; changed the certificate authentication prompt page to automatically log in the user after 10 seconds if no response from user is received

Support for loading CRL from LDAP directory; finished the CRL checking using the distribution points in the certificate; updated the instructions how to add X509 authentication to keycloak authentication flows; minor styling changes

Stashing x509 unit test related changes; added the steps to configure mutual SSL in WildFly to the summary document

A minor fix to throw a security exception when unable to check cert revocation status using OCSP; continue working on README

Changes to the formating of the readme

Added a list of features to readme

Fixed a potential bug in X509 cert user authenticator that may cause NPE if the client certificate does not define keyusage or extended key usage extensions

Fixed compile time errors in X509 validators caused by the changes to the user credentials model in upstream master

Removed a superfluous file created when merging x509 and main branches

X509 authentication: removed the PKIX path validation as superflous

Reverted changes to the AbstractAttributeMapper introduced during merging of x509 branch into main

Merge the unit tests from x509 branch

added mockito dependency to services project; changes to the x509 authenticators to expose methods in order to support unit tests; added a default ctor to CertificateValidator class to support unit testing; updated the direct grant and browser x509 authenticators to report consistent status messages; unit tests to validate X509 direct grant and browser authenticators; fixed OCSP validation to throw an exception if the certificate chain contains a single certificate; fixed the CRL revocation validation to only use CRL distribution point validation only if configured

CRL and OSCP mock tests using mock netty server. Changed the certificate validator to better support unit testing.

changes to the mockserver dependency to explicitly exclude xercesImpl that was causing SAMLParsingTest to fail

Added a utility class to build v3 certificates with optional extensions to facilitate X509 unit testing; removed supoerfluous certificate date validity check (undertow should be checking the certificate dates during PKIX path validation anyway)

X509: changes to make configuring the user identity extraction simplier for users - new identity sources to map certificate CN and email (E) attributes from X500 subject and issuer names directly rather than using regular expressions to parse them

X509 fixed a compile error caused by the changes to the user model in master

Integration tests to validate X509 client certificate authentication

Minor tweaks to X509 client auth related integration tests

CRLs to support x509 client cert auth integration tests

X509: reverted the changes to testrealm.json and updated the test to configure the realm at runtime

X509 - changes to the testsuite project configuration to specify a path to a trust store used to test x509 direct grant flow; integration tests to validate x509 authentication in browser and direct grant flows; updated the client certificate to extend its validatity dates; x509 integration tests and authenticators have been refactored to use a common configuration class

X509 separated the browser and direct grant x509 authenction integration tests

x509 updated the authenticator provider test to remove no longer supported cert thumbprint authenticator

x509 removed the dependency on mockito

x509 re-implemented OCSP certificate revocation client used to check revocation status when logging in with x509 certificate to work around the dependency on Sun OCSP implementation; integration tests to verify OCSP revocation requests

index.txt.attr is needed by openssl to run a simple OCSP server

x509: minor grammar fixes

Add OCSP stub responder to integration tests

This commit adds OCSP stub responder needed for the integration tests,
and eliminates the need to run external OCSP responder in order to run
the OCSP in X509OCSPResponderTest.

Replace printStackTrece with logging

This commit replaces call to printStackTrace that will end up going to
the stderr with logging statement of WARN severity.

Remove unused imports

Removed unused imports in
org.keycloak.authentication.authenticators.x509 package.

Parameterized Hashtable variable

Removed unused CertificateFactory variable

Declared serialVersionUID for Serializable class

Removed unused CertificateBuilder class

The CertificateBuilder was not used anywhere in the code, removing it to
prevent technical debt.

Removing unused variable declaration

`response` variable is not used in the test, removed it.

Made sure InputStreams are closed

Even though the InputStreams are memory based, added try-with-resources
to make sure that they are closed.

Removed deprecated usage of URLEncoder

Replaced invocation of deprecated method from URLEncoder with Encode
from Keycloak util package.

Made it more clear how to control OCSP stub responder in the tests

X509 Certificate user authentication: moved the integration unit tests into their own directory to fix a failing travis test job

KEYCLOAK-4335: reduced the logging level; added the instructions how to run X.509 related tests to HOW-TO-RUN.md doc; removed README.md from x509 folder; removed no longer used ocsp profile and fixed the exclusion filter; refactored the x509 base test class that was broken by the recent changes to the integration tests

KEYCLOAK-4335: fixed a few issues after rebasing
2017-03-17 05:24:57 -04:00
Stian Thorgersen 3551912506 Merge pull request #3954 from stianst/master
Bump to 3.1.0.CR1-SNAPSHOT
2017-03-16 15:01:35 +01:00
Stian Thorgersen a87ee04024 Bump to 3.1.0.CR1-SNAPSHOT 2017-03-16 14:21:40 +01:00
Stian Thorgersen cda563e672 Merge pull request #3952 from stianst/master
Added jboss parent to boms parent
2017-03-16 12:44:52 +01:00
Stian Thorgersen a434e0540b Added jboss parent to boms parent 2017-03-16 12:44:31 +01:00
vramik d0992ef9bd KEYCLOAK-4571 Adapt server-config-migration module for testing both project and product 2017-03-16 10:53:14 +01:00
Pavel Drozd c30cdb5411 Merge pull request #3932 from vmuzikar/KEYCLOAK-4169
KEYCLOAK-4169 Instructions on how to run UI and Welcome Page tests
2017-03-15 23:53:49 +01:00
Pavel Drozd b2d677256d Merge pull request #3877 from mhajas/KEYCLOAK-3955
KEYCLOAK-3955 Add CORS tests to integration arquillian testsuite
2017-03-15 23:52:03 +01:00
Bartosz Majsak a250f08b6c Removes trailing slash from the base url 2017-03-15 22:27:24 +01:00
Stian Thorgersen f44405207b Merge pull request #3828 from wildloop/master
verifySSL() - debug info
2017-03-15 09:55:42 +01:00
Stian Thorgersen feeac69197 Merge pull request #3888 from daklassen/KEYCLOAK-4421
KEYCLOAK-4421 Change any http maven urls to https to reduce build-time MITM vulnerability
2017-03-15 09:54:21 +01:00
Stian Thorgersen 2aa93d7d55 Merge pull request #3924 from daklassen/KEYCLOAK-2486
KEYCLOAK-2486: Update SimpleHTTP to use Apache HTTP Client
2017-03-15 09:50:06 +01:00
wildloop 80c9e23282 Update RequestAuthenticator.java 2017-03-15 09:14:48 +01:00
wildloop 366dee6575 Update RequestAuthenticator.java 2017-03-15 09:13:41 +01:00
Stian Thorgersen 44907503a4 Merge pull request #3935 from knutz3n/KEYCLOAK-4559
KEYCLOAK-4559 Filter users by realm id when search for user by attribute
2017-03-15 08:44:43 +01:00
Thomas Darimont b782892769 KEYCLOAK-4163 Improve support for e-mail addresses
Added support for user friendly email addresses as well as dedicated
reply-to addresses for emails being sent by Keycloak.
Both can be customized via the email settings per realm in
the admin-console.
User friendly email addresses use the format:
"Friendly Name"<email@example.org> and provide way to add a meaning
full name to an e-mail address.

We also allow to specify an optional envelope from bounce address.
If a mail sent to a user could not be delivered the email-provider
will sent a notification to that address.

See: https://en.wikipedia.org/wiki/Bounce_address

Add test for proper email headers in sent messages
2017-03-14 18:22:54 +01:00
Bill Burke 1974b34c29 Merge pull request #3928 from sebastienblanc/test-utilities
KEYCLOAK-4322 : adding a helper class
2017-03-14 11:32:49 -04:00
Bill Burke 6d51862057 Merge pull request #3897 from anderius/feature/KEYCLOAK-4504-redirect-logout
[WIP] Saml broker: Option to specify logout request binding
2017-03-14 11:32:26 -04:00
wildloop d723c608d6 Update RequestAuthenticator.java 2017-03-14 11:36:57 +01:00
Johannes Knutsen 9a0de676c4 KEYCLOAK-4559 Filter users by realm id when searching for user by user attribute 2017-03-14 11:05:12 +01:00
Stian Thorgersen a555f99b1a Merge pull request #3937 from sebastienblanc/document_sb_properties
KEYCLOAK-4565 : javadoc for adapter properties and add metada generator
2017-03-14 10:19:34 +01:00
David Klassen 32d3f760ec KEYCLOAK-4421: Change http url to https
Change any http maven urls to https to reduce build-time MITM vulnerability
2017-03-14 10:18:40 +01:00
Stian Thorgersen 99581748e0 Merge pull request #3921 from gmarziou/fix-french-plural
KEYCLOAK-4561 Fix plural error in French translation
2017-03-14 09:32:37 +01:00
Stian Thorgersen f0ae34d1ad Merge pull request #3885 from sk8ter/master
add Swedish translation for account, email, login
2017-03-14 09:31:36 +01:00
Stian Thorgersen 4f39cf8abd Merge pull request #3947 from ssilvert/master
KEYCLOAK-4535: Needless heading while adding or editing a Role
2017-03-14 08:56:21 +01:00
Stan Silvert e6df617cfc KEYCLOAK-4535: Needless heading while adding or editing a Role 2017-03-13 21:03:05 -04:00
Pedro Igor 9d1d22565c Merge pull request #3938 from pedroigor/authz-fixes
AuthZ Services Fixes
2017-03-13 15:20:41 -03:00
Gabriel Lavoie fb507048f5 KEYCLOAK-4563: Large user account ID and group ID may break distribution builds.
- Maven documentation recommends using POSIX tar format.
2017-03-13 13:28:51 -04:00
Pedro Igor e7e6314146 [KEYCLOAK-4555] - Fixes and improvements to evaluation code 2017-03-13 14:08:54 -03:00
Marek Posolda 649ca36ece Merge pull request #3945 from mposolda/master
KEYCLOAK-4572 AccountTest.changeProfileNoAccess unstable
2017-03-13 15:57:43 +01:00
Pavel Drozd 253c8a342b Merge pull request #3941 from pdrozd/KEYCLOAK-4569
KEYCLOAK-4569 SSSDTest rewrited to be usable in different enviroments
2017-03-13 15:50:06 +01:00
Pavel Drozd 71a9d51c56 Merge pull request #3940 from pdrozd/KEYCLOAK-4304
KEYCLOAK-4304 Updated Kerberos tests to be able to run them on differ…
2017-03-13 15:49:01 +01:00
Stian Thorgersen ef164f5e69 Merge pull request #3943 from stianst/TRAVIS
Add --no-snapshot-updates to Travis builds
2017-03-13 15:41:05 +01:00
Stian Thorgersen b0484409d4 Remove adapter tests from Travis as no tests where being ran 2017-03-13 14:42:39 +01:00
mposolda aa84709087 KEYCLOAK-4572 AccountTest.changeProfileNoAccess unstable 2017-03-13 13:58:46 +01:00
Stian Thorgersen adf3eaf8fe Merge pull request #3942 from stianst/KEYCLOAK-4570
KEYCLOAK-4570
2017-03-13 12:32:08 +01:00
Stian Thorgersen 4dcb8d2c2a Merge pull request #3931 from hmlnarik/KEYCLOAK-4552
KEYCLOAK-4552
2017-03-13 12:31:33 +01:00
Stian Thorgersen 2cf4518ffd Disable snapshot for repositories 2017-03-13 09:03:46 +01:00
Stian Thorgersen 3f29c68e92 Add --no-snapshot-updates to Travis builds 2017-03-13 08:53:03 +01:00
Stian Thorgersen a56dd1651b KEYCLOAK-4570
Boms should not use keycloak-parent
2017-03-13 08:34:52 +01:00
Pavel Drozd f32fc99e80 KEYCLOAK-4569 SSSDTest rewrited to be usable in different enviroments 2017-03-13 08:05:30 +01:00
Pavel Drozd b5433720c1 KEYCLOAK-4304 Updated Kerberos tests to be able to run them on different environment 2017-03-13 08:00:41 +01:00
Bill Burke 613f4bb4c6 Merge pull request #3939 from alexeykazakov/patch-1
KEYCLOAK-4568 Identity broker service may fail to validate client ses…
2017-03-11 19:39:39 -05:00
Alexey Kazakov 063f5303dd KEYCLOAK-4568 Identity broker service may fail to validate client session if there is more then one active session 2017-03-11 12:59:25 -08:00
Pedro Igor 45caea4dbd [KEYCLOAK-4549] - Scope Permission Form is not showing saved resource 2017-03-10 17:32:55 -03:00
sebastienblanc 68da8c23ad KEYCLOAK-4565 : javadoc for adapter properties and add metada generator 2017-03-10 18:13:19 +01:00
Pavel Drozd 282896b653 Merge pull request #3930 from vmuzikar/KEYCLOAK-4554-2
KEYCLOAK-4554 Fix WelcomePage test
2017-03-10 15:57:47 +01:00
Pavel Drozd 3884dd974a Merge pull request #3925 from vmuzikar/KEYCLOAK-4553
KEYCLOAK-4553 Truststore not found in Arquillian tests in "other" module
2017-03-10 15:56:40 +01:00
sebastienblanc 64f20b580a adding a helper class 2017-03-10 14:43:16 +01:00
Stian Thorgersen e7cd8d41c6 Merge pull request #3558 from glavoie/KEYCLOAK-3989
KEYCLOAK-3989: Replacing COMPOSITE_ROLE Collection with Set.
2017-03-10 12:00:59 +01:00
Vaclav Muzikar f3e842fdd9 KEYCLOAK-4169 Instructions on how to run UI and Welcome Page tests 2017-03-10 11:26:21 +01:00
Hynek Mlnarik 42954e84d9 KEYCLOAK-4552 2017-03-10 10:59:50 +01:00
Bill Burke 0ff4223184 Merge pull request #3922 from hmlnarik/KEYCLOAK-4288-SAML-logouts-are-not-invalidating-the-sessions-for-all-the-logged-in-applications
KEYCLOAK-4288 Invalidate sessions in cluster for SAML logouts
2017-03-09 19:13:37 -05:00
Bill Burke b618dbd97f Merge pull request #3926 from mrpardijs/KEYCLOAK-4360-Add-SAML-OneTimeUse-Condition
KEYCLOAK-4360: Add OneTimeUse condition to SAMLResponse
2017-03-09 19:09:02 -05:00
Bill Burke 213cffa9c5 Merge pull request #3929 from gmarziou/update-freeotp-url
Update URL for FreeOTP
2017-03-09 19:00:13 -05:00
Vaclav Muzikar dc2d2cdbde Merge branch 'master' of https://github.com/keycloak/keycloak into KEYCLOAK-4553 2017-03-09 16:54:08 +01:00
Vaclav Muzikar 8b888fdf0c KEYCLOAK-4554 Fix WelcomePage test 2017-03-09 16:41:54 +01:00
Gaël MARZIOU 46c6db1739 Update URL for FreeOTP
It was poniting to obsolete location: https://fedorahosted.org/freeotp/

Now pointing to: https://freeotp.github.io/
2017-03-09 16:20:28 +01:00
Pavel Drozd 11d93994c2 Merge pull request #3919 from vramik/KEYCLOAK-4210
KEYCLOAK-4210 remove redundant dependency
2017-03-09 15:49:55 +01:00
Mark Pardijs c78c0b73d3 KEYCLOAK-4360: Add OneTimeUse condition to SAMLResponse
Add OneTimeUse Condition to SAMLResponse when configured in client settings
2017-03-09 13:01:05 +01:00
Vaclav Muzikar 2175f66a30 KEYCLOAK-4553 Truststore not found in Arquillian tests in "other" module 2017-03-09 11:17:42 +01:00
David Klassen 7029ef80f8 KEYCLOAK-2486: Update SimpleHTTP to use Apache HTTP Client
Update SimpleHTTP to use Apache HTTP client under the covers.
2017-03-09 09:23:09 +01:00
Marek Posolda 16d5ca3378 Merge pull request #3859 from thomasdarimont/issue/KEYCLOAK-4205-role-mapper-value-as-array
KEYCLOAK-4205 Allow to return json arrays in Client and Realm Role Mappers
2017-03-09 08:47:29 +01:00
Stian Thorgersen 5b4e3434bb Merge pull request #3886 from anderius/feature/newlines-in-saml
KEYCLOAK-4489 SAML encrypted assertion with newlines fails during parsing
2017-03-09 08:29:55 +01:00
Thomas Darimont 1dea38bdbb KEYCLOAK-4205 Allow to return json arrays in Client and Realm Role Mappers
Previously the ClientRoleMapper and RealmRoleMapper returned
roles as a comma delimited String in OIDC tokens which
needed to be parsed by client applications.
We now support to generate the role information as JSON
arrays by setting "multi valued" to "true" in the
client role mapper or realm role mappers respectively
which makes it easier for clients to consume.

The default setting for "multi valued" is "false" to
remain backwards compatible.

An example AccessToken that shows the two modes can be found here:
https://gist.github.com/thomasdarimont/dff0cd691cd6e0b5e33c2eb4c76ae5e8
2017-03-08 20:56:56 +01:00
Gael MARZIOU 0fc4cd134f Fix plural error in French translation 2017-03-08 18:47:06 +01:00
Bill Burke efffcc5f41 Merge pull request #3915 from TeliaSoneraNorge/KEYCLOAK-4524
KEYCLOAK-4524
2017-03-08 10:08:04 -05:00
Bill Burke 6f2ace538f Merge pull request #3917 from reneploetz/master
KEYCLOAK-4537 Jetty 9.4 implementation (OIDC/SAML)
2017-03-08 09:44:33 -05:00
Stian Thorgersen 50af3212f1 Merge pull request #3920 from stianst/master
KEYCLOAK-4536 Added troubleshooting section to Cordova example
2017-03-08 12:25:01 +01:00
Stian Thorgersen e2e91ef098 KEYCLOAK-4536 Added troubleshooting section to Cordova example 2017-03-08 12:23:57 +01:00
vramik 0c4a1b1489 KEYCLOAK-4210 remove redundant dependency 2017-03-08 10:51:18 +01:00
Stian Thorgersen 61c3d6eb74 Merge pull request #3913 from sebastienblanc/adapter_dist
add adapters dist artifact
2017-03-08 09:10:56 +01:00
Pavel Drozd 62876b9694 Merge pull request #3912 from vmuzikar/KEYCLOAK-4526
KEYCLOAK-4526 Fix Node.js Arquillian tests
2017-03-07 21:53:30 +01:00
Pavel Drozd 739dae0846 Merge pull request #3908 from vramik/KEYCLOAK-4348
KEYCLOAK-4348 upgrade maven-surefire-plugin version
2017-03-07 21:52:24 +01:00
Pavel Drozd 7ab67d205b Merge pull request #3903 from tkyjovsk/KEYCLOAK-4515
KEYCLOAK-4515 Make it possible to clean-up other DB types than mysql or postgres
2017-03-07 21:50:48 +01:00
Anders Båtstrand 224c9c5395 KEYCLOAK-4489 Use event reader from AbstractParser, which handles newlines and whitespace. 2017-03-07 19:05:07 +01:00
wildloop 7904ce5a37 one-line debug log 2017-03-07 16:01:13 +01:00
Rene Ploetz e770a05db0 KEYCLOAK-4537 Jetty 9.4 implementation (OIDC/SAML) 2017-03-06 23:01:24 +01:00
Pavel Drozd 89c89b4867 Merge pull request #3873 from mhajas/KEYCLOAK-3961
KEYCLOAK-3961
2017-03-06 13:01:16 +01:00
mhajas 213ed6fa4b KEYCLOAK-3955 2017-03-06 10:22:06 +01:00
mhajas 280689055f KEYCLOAK-3961 2017-03-06 10:17:59 +01:00
Bill Burke 1d11cb468c Merge pull request #3914 from patriot1burke/master
KEYCLOAK-4501 KEYCLOAK-4511 KEYCLOAK-4513
2017-03-03 14:13:59 -05:00
Bill Burke 05e080624b import after each test 2017-03-03 11:32:48 -05:00
Bill Burke c6dc59f63e Merge remote-tracking branch 'upstream/master' 2017-03-03 11:00:32 -05:00
Martin Hardselius a0a85f62c6 KEYCLOAK-4524 possible to add identity prover mappers with same name into single identity provider
- unique name enforcement working
- test added
2017-03-03 16:40:49 +01:00
Bill Burke 3bb29e033b KEYCLOAK-4501, KEYCLOAK-4511, KEYCLOAK-4513 2017-03-03 09:48:52 -05:00
Bartosz Majsak beee0c1e67 Implements social login test for OpenShift 2017-03-03 14:55:40 +01:00
sebastienblanc 87c9c99259 add adapters dist artifact 2017-03-03 11:45:13 +01:00
Vaclav Muzikar b0b0bfdf76 KEYCLOAK-4526 Fix Node.js Arquillian tests 2017-03-03 11:08:13 +01:00
Bartosz Majsak 669b0143af Adds tooltip for URL and en translation 2017-03-02 20:24:52 +01:00
Bartosz Majsak 1a6bb2fedb Adds Openshift Identity Provider as part of social brokers 2017-03-02 15:14:57 +01:00
Marek Posolda b8767d13d5 Merge pull request #3907 from mposolda/cross-dc
KEYCLOAK-4520 Enable testsuite logging when running test from IDE
2017-03-02 12:23:36 +01:00
Marek Posolda 686f82342b Merge pull request #3905 from Dichotomia/patch-3
administrator Spelling mistake
2017-03-02 12:23:20 +01:00
Marek Posolda cfb8d25ff2 Merge pull request #3900 from KillerDiller/wellknownprovider-four-oh-four
KEYCLOAK-4519: Avoid NPE for unknown paths under .../.well-known/.
2017-03-02 12:22:35 +01:00
vramik a24070c2b0 KEYCLOAK-4348 upgrade maven-surefire-plugin version 2017-03-02 12:09:15 +01:00
mposolda 69e61398a6 KEYCLOAK-4520 Enable testsuite logging when running test from IDE 2017-03-02 10:50:50 +01:00
Stan Silvert 89768ef003 Merge pull request #3906 from ssilvert/update-migration-scripts
KEYCLOAK-4514: Update migration scripts according to changes to the
2017-03-01 15:54:57 -05:00
Stan Silvert 794defe6fc KEYCLOAK-4514: Update migration scripts according to changes to the
subsystem
2017-03-01 13:53:40 -05:00
Hynek Mlnarik 27ba4eb978 KEYCLOAK-4288 Tests for EAP6 and Wildfly 2017-03-01 15:17:39 +01:00
Hynek Mlnarik 3a0c2be885 KEYCLOAK-4288 AS 7 / EAP 6 2017-03-01 15:17:39 +01:00
Hynek Mlnarik 04da679628 KEYCLOAK-4288 Wildfly 2017-03-01 15:17:39 +01:00
Hynek Mlnarik 43be3fc409 KEYCLOAK-4288 Use SessionListener to keep track of local HTTP-SSO session mappings 2017-03-01 15:17:39 +01:00
Hynek Mlnarik 567393a102 KEYCLOAK-4288 Fix SAML logout session for Tomcat/EAP6
When logging out via application (via ?GLO=true query parameter),
CatalineSamlSessionStore does not expire session, while it does that
in logging by SAML session index.

This causes distributed sessions being invalidated only on node hanling
the request, but remains active in other nodes of the cluster. Then the
session can be resurrected on next cache replication back even to the
node where the logout was performed. This behaviour is fixed here.
2017-03-01 15:17:39 +01:00
Quentin Caillard 75851ee0b3 administrator Spelling mistake 2017-03-01 12:32:55 +01:00
Marek Posolda b54d7c37b6 Merge pull request #3890 from daklassen/KEYCLOAK-2994
KEYCLOAK-2994: Revise german translations
2017-03-01 12:22:44 +01:00
Marek Posolda 69cf7b4d0d Merge pull request #3891 from mikaoelitiana/KEYCLOAK-4497
Update french translation in admin console
2017-03-01 12:21:42 +01:00
Marek Posolda 4f4ae44a16 Merge pull request #3896 from thomasdarimont/issue/KEYCLOAK-4505-expose-clientSession-binding-to-ScriptBasedAuthenticator
KEYCLOAK-4505 Expose current clientSession binding to ScriptBasedAuthenticator
2017-03-01 12:17:29 +01:00
Marek Posolda 31191bdfc8 Merge pull request #3904 from mposolda/testsuite-import
KEYCLOAK-1590 Realm import per test class
2017-03-01 11:49:15 +01:00
mposolda 091b376624 KEYCLOAK-1590 Realm import per test class 2017-03-01 09:38:44 +01:00
Pavel Drozd 52fbe00c04 Merge pull request #3874 from vramik/KEYCLOAK-4258
KEYCLOAK-4258 add server-config-migration module to parent pom
2017-03-01 08:27:59 +01:00
Tomas Kyjovsky c94b7922aa Added profile jdbc-driver-depencency to arq. testsuite; changed jdbc module path from layers/base/com/${db} to layers/base/test/jdbc/${db} 2017-03-01 01:37:53 +01:00
Anders Båtstrand 8d82390843 KEYCLOAK-4504 New configuration option for SAML Broker:
* postBindingLogout: Indicates if POST or redirect should be used for the logout requests.

This applies to both IdP-initiated logout, and Keycloak-initiated logout. If unset (for example when upgrading Keycloak), the setting is initially set to the same as postBindingResponse.

The flag is also set when importing IdP metadata.
2017-02-28 12:08:22 +01:00
Bill Burke 0765b01189 Merge remote-tracking branch 'upstream/master' 2017-02-27 18:46:09 -05:00
Bill Burke b4f625e1ce KEYCLOAK-4501 2017-02-27 18:46:00 -05:00
Marek Posolda b5b0f433ac Merge pull request #3899 from hmlnarik/KEYCLOAK-4368-htmlUnit-for-adapter-tests-without-examples
KEYCLOAK-4368 Enable htmlUnit for adapter tests (not examples though)
2017-02-27 08:32:18 +01:00
Stefan Paletta bcbde3fdf0 Avoid NPE for unknown paths under .../.well-known/. 2017-02-27 02:42:02 +01:00
Hynek Mlnarik 1970e03361 KEYCLOAK-4368 Enable htmlUnit for adapter tests (not examples though) 2017-02-26 16:56:26 +01:00
Stian Thorgersen 07f99a946d Merge pull request #3895 from stianst/KEYCLOAK-943
KEYCLOAK-943 Added initial implementation for update profile
2017-02-24 15:17:46 +01:00
Stan Silvert 6ea9581c6c Merge pull request #3855 from tsabirgaliev/master
angular2-product-app: simplify KeycloakHttp
2017-02-24 08:09:31 -05:00
Thomas Darimont 18a8ed3e95 KEYCLOAK-4505 Expose current clientSession binding to ScriptBasedAuthenticator.
Previously the ScriptBasedAuthenticator did not expose the current
clientSession from the AuthenticationFlowContext.
In order to implement client specific authentications with javascript
one needs information about the current client.
2017-02-24 14:01:10 +01:00
Stian Thorgersen e2b1c97e26 KEYCLOAK-943 Added initial implementation for update profile 2017-02-24 13:19:29 +01:00
Tair Sabirgaliev 6a809a2009 update readme 2017-02-24 15:16:06 +06:00
Tair Sabirgaliev 6b808d78e6 refactor and implement unit and e2e tests 2017-02-24 14:13:09 +06:00
Tair Sabirgaliev 26edcdf6bc proper license and ng test 2017-02-24 06:38:09 +06:00
vramik f77670c4dd KEYCLOAK-4262 disable server-config-migration for distribution and add possibility to run it with profile 2017-02-23 14:46:05 +01:00
Tair Sabirgaliev 5a64d67404 Angular 2 PoC based on angular-cli generated project
- use `frontend-maven-plugin` to pull node/npm automatically
- tie `npm install` to relevant lifecycle (`mvn wildfly:deploy` automatically builds and includes build products into WAR)
- extern keycloak and product database base url, use `--env=war` to build a war colocated with keycloak and database app

Issues/Todos:
- when testing with `ng serve` will have to disable browser web security (product-database doesn’t allow cross-origin requests)
- no unit / e2e / arquillian tests for now
- `src/main/frontend/node_modules` is included in distribution build, this is a portability debt
2017-02-23 14:45:00 +06:00
Mika Andrianarijaona ceb5a3a04b Update french translation in admin console 2017-02-23 11:04:55 +03:00
David Klassen 999a3f62ac KEYCLOAK-2994: Revise german translations
Corrected a huge amount of typos. Improved some translations.
2017-02-23 08:45:51 +01:00
Stian Thorgersen ca64b90cbf Merge pull request #3889 from stianst/master
KEYCLOAK-4483
2017-02-23 04:26:36 +01:00
Stian Thorgersen 2a7f595d1c KEYCLOAK-4483
Overlay standalone differs from dist standalone
2017-02-22 19:44:01 +01:00
Pavel Drozd 089bde3571 Merge pull request #3852 from tkyjovsk/user-storage-tests
UserStorageTest migrated to Arquillian testsuite
2017-02-22 16:09:57 +01:00
Pavel Drozd 2f45183ee5 Merge pull request #3884 from vramik/KEYCLOAK-4262
KEYCLOAK-4262 make AbstractSamlTest class abstract
2017-02-22 16:08:51 +01:00
Tomas Kyjovsky a5677e87db UserStorageTest migrated to Arquillian testsuite 2017-02-22 13:54:11 +01:00
Stan Silvert 0d7b4bab11 Merge pull request #3883 from ssilvert/ace-warning
KEYCLOAK-4463: JS warnings caused by ui-ace while manipulating with
2017-02-22 07:33:57 -05:00
Viktor Kostov 2cf25b6c57 add Swedish translation for account, email, login 2017-02-22 11:51:30 +01:00
vramik 4fbb8ed994 KEYCLOAK-4262 make AbstractSamlTest class abstract 2017-02-22 10:20:34 +01:00
Stan Silvert 4f78312a98 KEYCLOAK-4463: JS warnings caused by ui-ace while manipulating with
mappers
2017-02-21 19:31:25 -05:00
Marek Posolda 48832f8ff4 Merge pull request #3880 from mposolda/hardcoded-ldap-mapper
KEYCLOAK-4433 Added HardcodedLDAPAttributeMapper
2017-02-21 11:20:02 +01:00
mposolda 098d8e915d KEYCLOAK-4433 Added HardcodedLDAPAttributeMapper 2017-02-21 08:29:57 +01:00
Marek Posolda 49e8918462 Merge pull request #3876 from mposolda/perf-htmlunit
KEYCLOAK-4368 Switch default WebDriver impl to htmlUnit
2017-02-20 22:49:36 +01:00
Stan Silvert 0f1e73facc Merge pull request #3878 from ssilvert/funny-realm-names
KEYCLOAK-4467: Realm name collides with sidebar navigation
2017-02-20 16:35:14 -05:00
mposolda f6bc0806d5 KEYCLOAK-4368 Switch default WebDriver impl to htmlUnit 2017-02-20 21:52:15 +01:00
Stan Silvert 3bf9428cc0 KEYCLOAK-4467: Realm name collides with sidebar navigation 2017-02-20 15:43:46 -05:00
Pavel Drozd ec32acec27 Merge pull request #3872 from mhajas/KEYCLOAK-4179
KEYCLOAK-4179
2017-02-20 15:44:29 +01:00
Pavel Drozd 152b4f13e7 Merge pull request #3871 from mhajas/KEYCLOAK-4626
KEYCLOAK-4626 KEYCLOAK-4261 KEYCLOAK-4181 KEYCLOAK-4160 Add tests for SAML issues
2017-02-20 15:43:38 +01:00
Pavel Drozd 284ef5992d Merge pull request #3868 from zschwarz/12-16-failing-ssl-tests-z
KEYCLOAK-4084 Fix ssl adapter tests
2017-02-20 15:42:19 +01:00
Stian Thorgersen faf0e98665 Merge pull request #3736 from guusdk/api-documentation
Improving the generated REST API documentation
2017-02-20 15:30:32 +01:00
Pedro Igor 4d614ed635 Merge pull request #3834 from ramunask/HttpMethod-null-pointer-fix
NPE fix for HttpMethod
2017-02-20 11:28:18 -03:00
Stian Thorgersen 3653d7ed9a Merge pull request #3762 from sldab/hide-providers
KEYCLOAK-4224 Allow hiding identity providers on login page
2017-02-17 12:04:35 +01:00
Stian Thorgersen eb5e30579d Merge pull request #3875 from stianst/master
Fix server dist broken due to userSessionPersister removed
2017-02-16 16:18:01 +01:00
Stian Thorgersen 1625e6c977 Fix server dist broken due to userSessionPersister removed 2017-02-16 16:15:40 +01:00
Pavel Drozd 6af06348bd Merge pull request #3806 from hmlnarik/KEYCLOAK-4191-OIDCProtocolMappersTest-sometimes-fails-on-mariadb
KEYCLOAK-4191 Fix for OIDCProtocolMappersTest on mariadb
2017-02-16 13:36:25 +01:00
vramik e960e45671 Enable server-config-migration for distribution 2017-02-16 13:00:27 +01:00
mhajas 5bce87d6e7 KEYCLOAK-4179 2017-02-16 10:50:10 +01:00
Stian Thorgersen 7db6d51a39 Merge pull request #3870 from stianst/MONGO-REMOVAL
KEYCLOAK-4384 Remove Mongo support
2017-02-16 10:50:04 +01:00
mhajas b1510c43ff KEYCLOAK-4160 2017-02-16 08:09:11 +01:00
mhajas 44c81910bf KEYCLOAK-4181 2017-02-16 08:04:42 +01:00
mhajas 27e390965e KEYCLOAK-4261 2017-02-16 08:04:23 +01:00
mhajas 119435ac76 KEYCLOAK-4262 Test for rejected consent 2017-02-16 08:04:06 +01:00
Pavel Drozd b31c38a158 Merge pull request #3862 from mhajas/KEYCLOAK-4329
KEYCLOAK-4329 Add test for empty KeyInfo
2017-02-16 07:52:13 +01:00
Stian Thorgersen 49ac3587b6 KEYCLOAK-4384 Remove Mongo support 2017-02-15 15:20:58 +01:00
Stian Thorgersen 06da1d164d Merge pull request #3866 from stianst/master
KEYCLOAK-4394 Use JBoss logging
2017-02-15 12:37:02 +01:00
mhajas f2a4fd029d KEYCLOAK-4084 Fix ssl adapter tests 2017-02-15 09:35:15 +01:00
Stian Thorgersen aa59c2f95f KEYCLOAK-4394 Use JBoss logging 2017-02-15 09:05:42 +01:00
Stian Thorgersen 8d5a8085a4 Merge pull request #3864 from sebastienblanc/springboot-starter
KEYCLOAK-4423 : Adding Spring Boot Starter
2017-02-15 08:54:10 +01:00
sebastienblanc 083f27f19d KEYCLOAK-4423 : Adding Spring Boot Adapter 2017-02-14 14:33:15 +01:00
Stian Thorgersen fe0b9e9893 Merge pull request #3850 from sebastienblanc/bom_update
added all the adapters in BOM
2017-02-14 13:09:41 +01:00
mhajas 91bcc24977 KEYCLOAK-4329 Add test for empty KeyInfo 2017-02-14 12:36:17 +01:00
Stian Thorgersen d72b67c460 Merge pull request #3857 from anderius/feature/KEYCLOAK-4392-component-id
KEYCLOAK-4392 Copy component id from representation to model
2017-02-14 09:43:38 +01:00
Bill Burke 68b5afed06 Merge pull request #3858 from patriot1burke/master
KEYCLOAK-4382
2017-02-13 13:34:41 -05:00
Bill Burke c3e72b11db KEYCLOAK-4382 2017-02-13 10:51:10 -05:00
Stan Silvert 224f93f25d Merge pull request #3782 from cargosoft/master
KEYCLOAK-4270 Custom login protocol doesn't show when creating a client
2017-02-13 07:58:21 -05:00
Anders Båtstrand 3af9f2f989 KEYCLOAK-4392 Copy component id from representation to model 2017-02-13 13:03:57 +01:00
Pavel Drozd 8668eff1b6 Merge pull request #3856 from mhajas/KEYCLOAK-3987
KEYCLOAK-3987 Add test for grant role from token
2017-02-13 10:43:32 +01:00
Pavel Drozd 3cec57da6a Merge pull request #3827 from mhajas/KEYCLOAK-4346
KEYCLOAK-4346 Validation tests are failing because of ban on server w…
2017-02-13 10:42:08 +01:00
Pavel Drozd 6602123b55 Merge pull request #3824 from mhajas/KEYCLOAK-4020
KEYCLOAK-4020 add test for boolean attribute
2017-02-13 10:41:04 +01:00
Pavel Drozd 767b4a2e2a Merge pull request #3811 from mhajas/KEYCLOAK-4286
KEYCLOAK-4286 Use desired version of JS-adapter
2017-02-13 10:39:56 +01:00
Pavel Drozd beb96b7f01 Merge pull request #3810 from vramik/KEYCLOAK-4337
KEYCLOAK-4337 Few fixes for testsuite
2017-02-13 10:38:31 +01:00
Pavel Drozd 4ede1174b7 Merge pull request #3805 from mhajas/KEYCLOAK-3841
KEYCLOAK-3841 Fix tests on windows
2017-02-13 10:37:32 +01:00
Stian Thorgersen e3a8bed5b2 Merge pull request #3853 from pedroigor/RHSSO-767
[RHSSO-767] - Wrong implementation of Request.getRelativePath causing failures on Tomcat-like adapters
2017-02-13 10:26:34 +01:00
Stian Thorgersen 4f214921e3 Merge pull request #3841 from mposolda/KEYCLOAK-4385
KEYCLOAK-4385 Added BundleBasedKeycloakConfigResolver
2017-02-13 10:25:44 +01:00
mhajas 00932f4eb3 KEYCLOAK-3987 Add test for grant role from token 2017-02-10 10:27:38 +01:00
Tair Sabirgaliev dbe87d6592 angular2-product-app: simplify KeycloakHttp 2017-02-10 05:41:49 +06:00
Pedro Igor 9416ee7224 [RHSSO-767] - Wrong implementation of Request.getRelativePath causing failures on Tomcat-like adapters 2017-02-09 21:27:28 -02:00
Bill Burke 75909a0add Merge pull request #3851 from patriot1burke/master
LDAP No-Import
2017-02-09 10:29:55 -05:00
Bill Burke d9633dc20c Merge remote-tracking branch 'upstream/master' 2017-02-09 09:13:00 -05:00
Bill Burke 75bee51ac1 console remote imported/unlink users 2017-02-09 09:11:48 -05:00
mhajas 7d203ed448 KEYCLOAK-4346 Validation tests are failing because of ban on server which provides some imports to SAML xsd 2017-02-09 14:15:45 +01:00
sebastienblanc bb9da83e52 added all the adapters in BOM 2017-02-09 11:15:07 +01:00
Stian Thorgersen 8e16e5d953 Merge pull request #3839 from stianst/SOCIAL_LOGIN_TEST
KEYCLOAK-4265 Social login tests
2017-02-09 10:15:17 +01:00
Stian Thorgersen 44180a68e6 Merge pull request #3845 from frelibert/KEYCLOAK-4378
KEYCLOAK-4378 New user attribute is not added after first login from …
2017-02-09 10:02:09 +01:00
Bill Burke cf5e2a1d20 unlink/remoteimported 2017-02-08 19:48:22 -05:00
Stian Thorgersen ceece3dce4 Merge pull request #3847 from stianst/KEYCLOAK-4008-CHECKSUMS
KEYCLOAK-4008 Include checksums in download files
2017-02-08 20:05:39 +01:00
Stian Thorgersen 520839a29b Merge pull request #3835 from mposolda/KEYCLOAK-4371
KEYCLOAK-4371 Offline Tokens still useless When SSO Session Max is Re…
2017-02-08 15:42:31 +01:00
Stian Thorgersen a6b1e4f5f7 Merge pull request #3829 from mposolda/master
KEYCLOAK-4364 Fix OpenLDAP issue with renaming DN
2017-02-08 15:40:42 +01:00
Stian Thorgersen c4df0d2690 Merge pull request #3843 from pedroigor/KEYCLOAK-4373
[KEYCLOAK-4373] - Adapter Feature Pack is missing keycloak-authz-client
2017-02-08 14:58:33 +01:00
Stian Thorgersen 3de77b7be9 KEYCLOAK-4008 Include checksums in download files 2017-02-08 14:51:36 +01:00
Frederik Libert f3a552ac9d KEYCLOAK-4378 New user attribute is not added after first login from broker 2017-02-07 15:37:16 +01:00
Pedro Igor 27c0f783bc [KEYCLOAK-4373] - Adapter Feature Pack is missing keycloak-authz-client 2017-02-07 08:43:53 -02:00
mposolda 72a5d03f34 KEYCLOAK-4385 Added BundleBasedKeycloakConfigResolver 2017-02-06 21:24:20 +01:00
Stian Thorgersen 5b5dc3e442 KEYCLOAK-4265 Social login tests 2017-02-06 13:50:10 +01:00
Stian Thorgersen 1c7de24084 Merge pull request #3832 from stianst/KEYCLOAK-4370
KEYCLOAK-4370 Prevent LDAP provider from being migrated twice
2017-02-06 08:21:30 +01:00
Bill Burke f157e2e637 LDAP No-Import: more tests 2017-02-05 09:41:52 -05:00
Bill Burke f128be9b31 LDAP No-Import 2017-02-04 10:29:34 -05:00
mposolda 8a16ab52a9 KEYCLOAK-4371 Offline Tokens still useless When SSO Session Max is Reached and normal userSession expired 2017-02-03 11:55:58 +01:00
Ramūnas Kraujutis b693a3ee47 In case of PKI validation exception HttpMethod throws NPE, because bytes value is null. 2017-02-03 11:24:30 +02:00
Stian Thorgersen f73aaef67a KEYCLOAK-4370 Prevent LDAP provider from being migrated twice 2017-02-03 10:05:57 +01:00
Stian Thorgersen 652152f167 Merge pull request #3825 from stianst/KEYCLOAK-4338
Various fixes to JS adapter
2017-02-03 08:58:44 +01:00
Takashi Norimatsu 6bab704bba KEYCLOAK-2604 Proof Key for Code Exchange by OAuth Public Clients - RFC
7636 - Arquillian Test Cases
2017-02-03 14:41:36 +09:00
Takashi Norimatsu fe5fe4c968 KEYCLOAK-2604 Proof Key for Code Exchange by OAuth Public Clients - RFC
7636 - Client Side Implementation
2017-02-03 12:02:54 +09:00
Takashi Norimatsu 88bfa563df KEYCLOAK-2604 Proof Key for Code Exchange by OAuth Public Clients - RFC
7636 - Server Side Implementation
2017-02-03 10:38:54 +09:00
Agile Developer d60c3b7c0c missing import 2017-02-03 00:47:41 +01:00
mposolda 73cad40fb7 KEYCLOAK-4364 Fix OpenLDAP issue with renaming DN 2017-02-02 22:21:29 +01:00
Agile Developer cde3e87ad9 verifySSL() - debug info
DEBUG report like this:

SSL Verification: 
		passed: true, request is secure: true, 
		SSL is required for: EXTERNAL, 
		SSL is required for remote addr 192.168.100.123: false
2017-02-02 21:18:14 +01:00
Stian Thorgersen 68a171f36c Merge pull request #3823 from ssilvert/split-domain-script
KEYCLOAK-4362: Split domain script into two separate scripts
2017-02-02 21:08:18 +01:00
Stian Thorgersen be2378a424 Merge pull request #3820 from patriot1burke/master
KEYCLOAK-4363
2017-02-02 11:32:30 +01:00
Stian Thorgersen 9aa2dacec9 KEYCLOAK-4366 Issues when keycloak.js is initialized with token 2017-02-02 10:57:03 +01:00
mhajas ddf9301ceb KEYCLOAK-4020 add test for boolean attribute 2017-02-02 09:47:52 +01:00
vramik 7abe140621 resolve 'There is no context available for qualifier' message 2017-02-02 09:20:03 +01:00
Stian Thorgersen ee62c52543 KEYCLOAK-4338 KEYCLOAK-4331 Fixes to session iframe 2017-02-02 08:12:29 +01:00
Stan Silvert b4e4cbcbaa KEYCLOAK-4262: Update pom version 2017-02-01 14:38:52 -05:00
Stan Silvert a7c3d1b8df KEYCLOAK-4262 Split migration-domain script into two separate scripts 2017-02-01 14:23:20 -05:00
Bill Burke 79dede8e78 KEYCLOAK-4363 2017-02-01 10:19:15 -05:00
Bill Burke 1d04d56bdb Merge pull request #3816 from patriot1burke/master
KEYCLOAK-4218
2017-02-01 08:55:10 -05:00
Bill Burke 0d308e2b69 KEYCLOAK-4218 2017-01-31 15:15:49 -05:00
Pedro Igor 0c16a15b7d Merge pull request #3814 from pedroigor/authz-export-fixes
Authz export fixes
2017-01-31 15:57:40 -02:00
Marek Posolda beebeaa265 Merge pull request #3813 from mposolda/master
KEYCLOAK-4339 MigrationTest fails to run
2017-01-31 16:51:11 +01:00
Pedro Igor c705a8ffc8 [KEYCLOAK-4340] - Exporting authorization settings is updating policies with wrong data 2017-01-31 13:11:14 -02:00
Pedro Igor 57c74e3f39 [KEYCLOAK-4341] - Resources are not properly exported when exporting authorization settings 2017-01-31 13:10:25 -02:00
mposolda f92dd6bd16 KEYCLOAK-4339 MigrationTest fails to run 2017-01-31 16:00:16 +01:00
mhajas 99e1482e06 KEYCLOAK-4286 Use desired version of JS-adapter 2017-01-31 14:04:14 +01:00
vramik aec59a7e91 refactor asserts in ExportImportTest to be more verbose 2017-01-31 13:24:06 +01:00
vramik 9a16805f17 assumeCommunity for AccountPageTest.testLocalizedReferrerLinkContent 2017-01-31 13:22:16 +01:00
vramik 2fd0c38ad1 Removed unused import from LDAPBinaryAttributesTest 2017-01-31 13:18:22 +01:00
Marek Posolda 2990703aeb Merge pull request #3809 from mposolda/master
KEYCLOAK-4169 Add how-to-run.md to testsuite
2017-01-31 09:11:06 +01:00
mposolda acf2e30c2f Fix MigrationTest 2017-01-30 22:23:19 +01:00
mposolda 5c5b7a33d3 KEYCLOAK-4169 Add initial testsuite how-to 2017-01-30 22:23:08 +01:00
Stian Thorgersen e28ca0ae61 Merge pull request #3807 from hmlnarik/KEYCLOAK-4329-NPE-when-not-providing-KeyInfo-element-in-IdP-initiated-SSO-SAML-
KEYCLOAK-4329 Fix NPE when not providing KeyInfo element in IdP initiated SSO SAML
2017-01-30 15:28:38 +01:00
Hynek Mlnarik ad0630d04f KEYCLOAK-4329 Fix NPE when not providing KeyInfo element in IdP initiated SSO SAML 2017-01-30 11:40:48 +01:00
Hynek Mlnarik 4d362fe9ca KEYCLOAK-4191 Fix for OIDCProtocolMappersTest on mariadb 2017-01-30 10:52:17 +01:00
Bill Burke bb77ab4a81 account link tests 2017-01-27 17:37:08 -05:00
Marek Posolda b42af99866 Merge pull request #3804 from mposolda/master
KEYCLOAK-4285 Adapter tests for examples fail in Wildfly/EAP6
2017-01-27 21:26:53 +01:00
mhajas 1a073629ec KEYCLOAK-3841 2017-01-27 14:43:46 +01:00
mposolda 265522a2e3 KEYCLOAK-4285 Adapter tests for examples fail in Wildfly/EAP6 2017-01-27 14:26:21 +01:00
Stian Thorgersen c10be4b1cf Merge pull request #3802 from stianst/RUN-TEST-ON-KC
KEYCLOAK-3729 Ability to run tests within Keycloak server
2017-01-27 13:45:51 +01:00
Stian Thorgersen 065c931a83 Merge pull request #3803 from stianst/BOMS
KEYCLOAK-4195 Keycloak adapter and SPI bom
2017-01-27 13:44:53 +01:00
Stian Thorgersen 7210ea36d2 KEYCLOAK-4195 Keycloak adapter and SPI bom 2017-01-27 12:19:40 +01:00
Stian Thorgersen 5fd3eb2990 KEYCLOAK-3729 Ability to run tests within Keycloak server 2017-01-27 12:14:19 +01:00
Stian Thorgersen 3a366dd0a6 Merge pull request #3800 from mstruk/KEYCLOAK-4324
KEYCLOAK-4324 Upgrade and unify Aesh version to 0.66.12
2017-01-27 09:23:29 +01:00
Marek Posolda 1674bf1643 Merge pull request #3799 from mposolda/master
KEYCLOAK-4271 Migration test for offline tokens
2017-01-26 18:50:30 +01:00
Marko Strukelj 3e13ffda65 KEYCLOAK-4324 Upgrade and unify Aesh version to 0.66.12 2017-01-26 18:08:48 +01:00
mposolda 42ad8aec64 KEYCLOAK-4271 Migration test for offline tokens 2017-01-26 17:19:03 +01:00
Marek Posolda 835d4c0aad Merge pull request #3798 from mposolda/master
KEYCLOAK-2813 Remove LegacyImportTest as the legacy JSON export/impor…
2017-01-26 12:13:51 +01:00
Stian Thorgersen ef9006e1a3 Merge pull request #3797 from stianst/master
Bump version to 3.0.0.CR1
2017-01-26 10:17:15 +01:00
mposolda a8e2c8ef31 KEYCLOAK-2813 Remove LegacyImportTest as the legacy JSON export/import tested with MigrationTest 2017-01-26 09:48:29 +01:00
Stian Thorgersen 6f22f88d85 Bump version to 3.0.0.CR1 2017-01-26 06:18:11 +01:00
Dmitry Telegin 5bacd2919d KEYCLOAK-4270 Custom login protocol doesn't show when creating a client 2017-01-21 01:46:34 +03:00
Slawomir Dabek 9bb65ba9b7 KEYCLOAK-4224 Allow hiding identity providers on login page 2017-01-17 14:32:59 +01:00
Guus der Kinderen ba73ab1c2a API documentation: Overview to left-hand side 2017-01-10 17:08:32 +01:00
Guus der Kinderen 45f5fa6a74 API documentation: Introduce and group by tags.
This commit introduces grouping of the documented REST resources. The grouping is based
on a free-form name of a resource (a 'tag' in Swagger terminology), which is introduced
by adding a @resource javadoc tag to every Resource class.
2017-01-10 17:08:27 +01:00
Guus der Kinderen 50b7dbe7b2 API documentation: Update dependencies. 2017-01-10 17:08:14 +01:00
Gabriel Lavoie 4910b35d69 KEYCLOAK-3989: Replacing COMPOSITE_ROLE Collection with Set.
- Hibernate optimization that avoids deleting/re-inserting all composite roles when adding/removing a composite.
2016-11-28 09:43:05 -05:00
1641 changed files with 178069 additions and 25628 deletions

No files matched your search

+1 -2
View File
@@ -16,7 +16,6 @@ env:
- TESTS=group2
- TESTS=group3
- TESTS=group4
- TESTS=adapter
- TESTS=old
jdk:
@@ -26,7 +25,7 @@ before_script:
- export MAVEN_SKIP_RC=true
install:
- travis_wait 60 mvn install -Pdistribution -DskipTests=true -B -V -q
- travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTests=true -B -V -q
script:
- ./travis-run-tests.sh $TESTS
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -85,6 +85,9 @@ public class KeycloakDeployment {
protected int publicKeyCacheTtl;
private PolicyEnforcer policyEnforcer;
// https://tools.ietf.org/html/rfc7636
protected boolean pkce = false;
public KeycloakDeployment() {
}
@@ -414,4 +417,14 @@ public class KeycloakDeployment {
public PolicyEnforcer getPolicyEnforcer() {
return policyEnforcer;
}
// https://tools.ietf.org/html/rfc7636
public boolean isPkce() {
return pkce;
}
public void setPkce(boolean pkce) {
this.pkce = pkce;
}
}
@@ -98,6 +98,11 @@ public class KeycloakDeploymentBuilder {
deployment.setCorsAllowedMethods(adapterConfig.getCorsAllowedMethods());
}
// https://tools.ietf.org/html/rfc7636
if (adapterConfig.isPkce()) {
deployment.setPkce(true);
}
deployment.setBearerOnly(adapterConfig.isBearerOnly());
deployment.setAutodetectBearerOnly(adapterConfig.isAutodetectBearerOnly());
deployment.setEnableBasicAuth(adapterConfig.isEnableBasicAuth());
@@ -24,6 +24,7 @@ import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.common.enums.SslRequired;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -160,7 +161,8 @@ public abstract class RequestAuthenticator {
protected boolean verifySSL() {
if (!facade.getRequest().isSecure() && deployment.getSslRequired().isRequired(facade.getRequest().getRemoteAddr())) {
log.warn("SSL is required to authenticate");
log.warnf("SSL is required to authenticate. Remote address %s is secure: %s, SSL required for: %s .",
facade.getRequest().getRemoteAddr(), facade.getRequest().isSecure(), deployment.getSslRequired().name());
return true;
}
return false;
@@ -33,6 +33,8 @@ import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.JsonSerialization;
import org.jboss.logging.Logger;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -46,6 +48,8 @@ import java.util.List;
*/
public class ServerRequest {
private static Logger logger = Logger.getLogger(ServerRequest.class);
public static class HttpFailure extends Exception {
private int status;
private String error;
@@ -136,6 +140,62 @@ public class ServerRequest {
}
}
// https://tools.ietf.org/html/rfc7636#section-4
public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri, String sessionId, String codeVerifier) throws IOException, HttpFailure {
List<NameValuePair> formparams = new ArrayList<>();
redirectUri = stripOauthParametersFromRedirect(redirectUri);
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, "authorization_code"));
formparams.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
formparams.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
if (sessionId != null) {
formparams.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, sessionId));
formparams.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, HostUtils.getHostName()));
}
// https://tools.ietf.org/html/rfc7636#section-4
if (codeVerifier != null) {
logger.debugf("add to POST parameters of Token Request, codeVerifier = %s", codeVerifier);
formparams.add(new BasicNameValuePair(OAuth2Constants.CODE_VERIFIER, codeVerifier));
} else {
logger.debug("add to POST parameters of Token Request without codeVerifier");
}
HttpPost post = new HttpPost(deployment.getTokenUrl());
ClientCredentialsProviderUtils.setClientCredentials(deployment, post, formparams);
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
post.setEntity(form);
HttpResponse response = deployment.getClient().execute(post);
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (status != 200) {
error(status, entity);
}
if (entity == null) {
throw new HttpFailure(status, null);
}
InputStream is = entity.getContent();
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int c;
while ((c = is.read()) != -1) {
os.write(c);
}
byte[] bytes = os.toByteArray();
String json = new String(bytes);
try {
return JsonSerialization.readValue(json, AccessTokenResponse.class);
} catch (IOException e) {
throw new IOException(json, e);
}
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
}
public static AccessTokenResponse invokeRefresh(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
@@ -17,7 +17,6 @@
*/
package org.keycloak.adapters.authorization;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -29,10 +28,8 @@ import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.resource.ProtectedResource;
import org.keycloak.authorization.client.ClientAuthorizationContext;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
@@ -56,7 +53,7 @@ public abstract class AbstractPolicyEnforcer {
this.policyEnforcer = policyEnforcer;
this.enforcerConfig = policyEnforcer.getEnforcerConfig();
this.authzClient = policyEnforcer.getClient();
this.pathMatcher = new PathMatcher();
this.pathMatcher = policyEnforcer.getPathMatcher();
this.paths = policyEnforcer.getPaths();
}
@@ -74,7 +71,6 @@ public abstract class AbstractPolicyEnforcer {
if (accessToken != null) {
Request request = httpFacade.getRequest();
Response response = httpFacade.getResponse();
String path = getPath(request);
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
@@ -86,7 +82,12 @@ public abstract class AbstractPolicyEnforcer {
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
response.sendError(403, "Could not find a configuration for path [" + path + "].");
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
return createAuthorizationContext(accessToken);
}
handleAccessDenied(httpFacade);
return createEmptyAuthorizationContext(false);
}
@@ -95,20 +96,21 @@ public abstract class AbstractPolicyEnforcer {
return createEmptyAuthorizationContext(true);
}
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
Set<String> requiredScopes = getRequiredScopes(pathConfig, request);
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
if (isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
}
}
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
response.sendError(403, "Authorization failed.");
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
if (!challenge(pathConfig, requiredScopes, httpFacade)) {
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
handleAccessDenied(httpFacade);
}
}
}
@@ -169,6 +171,10 @@ public abstract class AbstractPolicyEnforcer {
return false;
}
protected void handleAccessDenied(OIDCHttpFacade httpFacade) {
httpFacade.getResponse().sendError(403);
}
private boolean isDefaultAccessDeniedUri(Request request, PolicyEnforcerConfig enforcerConfig) {
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
@@ -198,7 +204,7 @@ public abstract class AbstractPolicyEnforcer {
}
private AuthorizationContext createEmptyAuthorizationContext(final boolean granted) {
return new AuthorizationContext() {
return new ClientAuthorizationContext(authzClient) {
@Override
public boolean hasPermission(String resourceName, String scopeName) {
return granted;
@@ -226,32 +232,6 @@ public abstract class AbstractPolicyEnforcer {
};
}
private PathConfig resolvePathConfig(PathConfig originalConfig, Request request) {
String path = getPath(request);
if (originalConfig.hasPattern()) {
ProtectedResource resource = this.authzClient.protection().resource();
Set<String> search = resource.findByFilter("uri=" + path);
if (!search.isEmpty()) {
// resource does exist on the server, cache it
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
PathConfig config = PolicyEnforcer.createPathConfig(targetResource);
config.setScopes(originalConfig.getScopes());
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
config.setEnforcementMode(originalConfig.getEnforcementMode());
this.policyEnforcer.addPath(config);
return config;
}
}
return originalConfig;
}
private String getPath(Request request) {
return request.getRelativePath();
}
@@ -273,7 +253,7 @@ public abstract class AbstractPolicyEnforcer {
}
private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
return new AuthorizationContext(accessToken, this.paths);
return new ClientAuthorizationContext(accessToken, this.paths, authzClient);
}
private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
@@ -56,6 +56,9 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending Entitlement challenge");
}
}
private void challengeUmaAuthentication(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
@@ -66,6 +69,9 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending UMA challenge");
}
}
private String getPermissionTicket(PathConfig pathConfig, Set<String> requiredScopes, AuthzClient authzClient) {
@@ -83,6 +83,12 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
@Override
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
handleAccessDenied(facade);
return true;
}
@Override
protected void handleAccessDenied(OIDCHttpFacade facade) {
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
HttpFacade.Response response = facade.getResponse();
@@ -92,8 +98,6 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
} else {
response.sendError(403);
}
return true;
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
@@ -0,0 +1,170 @@
/*
* 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.authorization;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PathCache {
/**
* The load factor.
*/
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private final Map<String, CacheEntry> cache;
private final AtomicBoolean writing = new AtomicBoolean(false);
private final long maxAge;
/**
* Creates a new instance.
*
* @param maxEntries the maximum number of entries to keep in the cache
*/
public PathCache(int maxEntries) {
this(maxEntries, -1);
}
/**
* Creates a new instance.
*
* @param maxEntries the maximum number of entries to keep in the cache
* @param maxAge the time in milliseconds that an entry can stay in the cache. If {@code -1}, entries never expire
*/
public PathCache(final int maxEntries, long maxAge) {
cache = new LinkedHashMap<String, CacheEntry>(16, DEFAULT_LOAD_FACTOR, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return cache.size() > maxEntries;
}
};
this.maxAge = maxAge;
}
public void put(String uri, PathConfig newValue) {
try {
if (parkForWriteAndCheckInterrupt()) {
return;
}
CacheEntry cacheEntry = cache.get(uri);
if (cacheEntry == null) {
cache.put(uri, new CacheEntry(uri, newValue, maxAge));
}
} finally {
writing.lazySet(false);
}
}
public PathConfig get(String uri) {
if (parkForReadAndCheckInterrupt()) {
return null;
}
CacheEntry cached = cache.get(uri);
if (cached != null) {
return removeIfExpired(cached);
}
return null;
}
public void remove(String key) {
try {
if (parkForWriteAndCheckInterrupt()) {
return;
}
cache.remove(key);
} finally {
writing.lazySet(false);
}
}
private PathConfig removeIfExpired(CacheEntry cached) {
if (cached == null) {
return null;
}
if (cached.isExpired()) {
remove(cached.key());
return null;
}
return cached.value();
}
private boolean parkForWriteAndCheckInterrupt() {
while (!writing.compareAndSet(false, true)) {
LockSupport.parkNanos(1L);
if (Thread.interrupted()) {
return true;
}
}
return false;
}
private boolean parkForReadAndCheckInterrupt() {
while (writing.get()) {
LockSupport.parkNanos(1L);
if (Thread.interrupted()) {
return true;
}
}
return false;
}
private static final class CacheEntry {
final String key;
final PathConfig value;
final long expiration;
CacheEntry(String key, PathConfig value, long maxAge) {
this.key = key;
this.value = value;
if(maxAge == -1) {
expiration = -1;
} else {
expiration = System.currentTimeMillis() + maxAge;
}
}
String key() {
return key;
}
PathConfig value() {
return value;
}
boolean isExpired() {
return expiration != -1 ? System.currentTimeMillis() > expiration : false;
}
}
}
@@ -17,93 +17,226 @@
*/
package org.keycloak.adapters.authorization;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.resource.ProtectedResource;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class PathMatcher {
private static final String ANY_RESOURCE_PATTERN = "/*";
private static final char WILDCARD = '*';
private final AuthzClient authzClient;
// TODO: make this configurable
private PathCache cache = new PathCache(100, 30000);
PathConfig matches(final String requestedUri, Map<String, PathConfig> paths) {
PathConfig pathConfig = paths.get(requestedUri);
public PathMatcher(AuthzClient authzClient) {
this.authzClient = authzClient;
}
public PathConfig matches(final String targetUri, Map<String, PathConfig> paths) {
PathConfig pathConfig = paths.get(targetUri) == null ? cache.get(targetUri) : paths.get(targetUri);
if (pathConfig != null) {
return pathConfig;
}
PathConfig actualConfig = null;
PathConfig matchingAnyPath = null;
PathConfig matchingAnySuffixPath = null;
for (PathConfig entry : paths.values()) {
String protectedUri = entry.getPath();
String selectedUri = null;
String expectedUri = entry.getPath();
String matchingUri = null;
if (protectedUri.equals(ANY_RESOURCE_PATTERN) && actualConfig == null) {
selectedUri = protectedUri;
if (exactMatch(expectedUri, targetUri, expectedUri)) {
matchingUri = expectedUri;
}
int suffixIndex = protectedUri.indexOf(ANY_RESOURCE_PATTERN + ".");
if (isTemplate(expectedUri)) {
String templateUri = buildUriFromTemplate(expectedUri, targetUri);
if (suffixIndex != -1) {
String protectedSuffix = protectedUri.substring(suffixIndex + ANY_RESOURCE_PATTERN.length());
if (requestedUri.endsWith(protectedSuffix)) {
selectedUri = protectedUri;
}
}
if (protectedUri.equals(requestedUri)) {
selectedUri = protectedUri;
}
if (protectedUri.endsWith(ANY_RESOURCE_PATTERN)) {
String formattedPattern = removeWildCardsFromUri(protectedUri);
if (!formattedPattern.equals("/") && requestedUri.startsWith(formattedPattern)) {
selectedUri = protectedUri;
}
if (!formattedPattern.equals("/") && formattedPattern.endsWith("/") && formattedPattern.substring(0, formattedPattern.length() - 1).equals(requestedUri)) {
selectedUri = protectedUri;
}
}
int startRegex = protectedUri.indexOf('{');
if (startRegex != -1) {
String prefix = protectedUri.substring(0, startRegex);
if (requestedUri.startsWith(prefix)) {
selectedUri = protectedUri;
}
}
if (selectedUri != null) {
selectedUri = protectedUri;
}
if (selectedUri != null) {
if (actualConfig == null) {
actualConfig = entry;
} else {
if (actualConfig.equals(ANY_RESOURCE_PATTERN)) {
actualConfig = entry;
if (templateUri != null) {
if (exactMatch(expectedUri, targetUri, templateUri)) {
matchingUri = templateUri;
entry = resolvePathConfig(entry, targetUri);
}
}
}
if (protectedUri.startsWith(removeWildCardsFromUri(actualConfig.getPath()))) {
actualConfig = entry;
if (matchingUri != null) {
StringBuilder path = new StringBuilder(expectedUri);
int patternIndex = path.indexOf("/" + WILDCARD);
if (patternIndex != -1) {
path.delete(patternIndex, path.length());
}
patternIndex = path.indexOf("{");
if (patternIndex != -1) {
path.delete(patternIndex, path.length());
}
String pathString = path.toString();
if ("".equals(pathString)) {
pathString = "/";
}
if (matchingUri.equals(targetUri)) {
cache.put(targetUri, entry);
return entry;
}
if (WILDCARD == expectedUri.charAt(expectedUri.length() - 1)) {
matchingAnyPath = entry;
} else {
int suffixIndex = expectedUri.indexOf(WILDCARD + ".");
if (suffixIndex != -1) {
String protectedSuffix = expectedUri.substring(suffixIndex + 1);
if (targetUri.endsWith(protectedSuffix)) {
matchingAnySuffixPath = entry;
}
}
}
}
}
return actualConfig;
if (matchingAnySuffixPath != null) {
cache.put(targetUri, matchingAnySuffixPath);
return matchingAnySuffixPath;
}
if (matchingAnyPath != null) {
cache.put(targetUri, matchingAnyPath);
}
return matchingAnyPath;
}
private String removeWildCardsFromUri(String protectedUri) {
return protectedUri.replaceAll("/[*]", "/");
private boolean exactMatch(String expectedUri, String targetUri, String value) {
if (targetUri.equals(value)) {
return value.equals(targetUri);
}
if (endsWithWildcard(expectedUri)) {
return targetUri.startsWith(expectedUri.substring(0, expectedUri.length() - 2));
}
String suffix = "/*.";
int suffixIndex = expectedUri.indexOf(suffix);
if (suffixIndex != -1) {
return targetUri.endsWith(expectedUri.substring(suffixIndex + suffix.length() - 1));
}
return false;
}
public String buildUriFromTemplate(String expectedUri, String targetUri) {
int patternStartIndex = expectedUri.indexOf("{");
if (patternStartIndex == -1 || patternStartIndex >= targetUri.length()) {
return null;
}
if (expectedUri.split("/").length > targetUri.split("/").length) {
return null;
}
char[] expectedUriChars = expectedUri.toCharArray();
char[] matchingUri = Arrays.copyOfRange(expectedUriChars, 0, patternStartIndex);
int matchingUriLastIndex = matchingUri.length;
String targetUriParams = targetUri.substring(patternStartIndex);
if (Arrays.equals(matchingUri, Arrays.copyOf(targetUri.toCharArray(), matchingUri.length))) {
matchingUri = Arrays.copyOf(matchingUri, targetUri.length());
int paramIndex = 0;
for (int i = patternStartIndex; i < expectedUriChars.length; i++) {
if (matchingUriLastIndex >= matchingUri.length) {
break;
}
char c = expectedUriChars[i];
if (c == '{' || c == '*') {
String[] params = targetUriParams.split("/");
for (int k = paramIndex; k <= (c == '*' ? params.length : paramIndex); k++) {
if (k == params.length) {
break;
}
int paramLength = params[k].length();
if (matchingUriLastIndex + paramLength > matchingUri.length) {
return null;
}
for (int j = 0; j < paramLength; j++) {
matchingUri[matchingUriLastIndex++] = params[k].charAt(j);
}
if (c == '*' && matchingUriLastIndex < matchingUri.length) {
matchingUri[matchingUriLastIndex++] = '/';
}
}
i = expectedUri.indexOf('}', i);
} else {
if (c == '/') {
paramIndex++;
}
matchingUri[matchingUriLastIndex++] = c;
}
}
if (matchingUri[matchingUri.length - 1] == '\u0000') {
return null;
}
return String.valueOf(matchingUri);
}
return null;
}
public boolean endsWithWildcard(String expectedUri) {
return WILDCARD == expectedUri.charAt(expectedUri.length() - 1);
}
private boolean isTemplate(String uri) {
return uri.indexOf("{") != -1;
}
private PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
if (originalConfig.hasPattern()) {
ProtectedResource resource = this.authzClient.protection().resource();
Set<String> search = resource.findByFilter("uri=" + path);
if (!search.isEmpty()) {
// resource does exist on the server, cache it
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
PathConfig config = PolicyEnforcer.createPathConfig(targetResource);
config.setScopes(originalConfig.getScopes());
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
config.setEnforcementMode(originalConfig.getEnforcementMode());
return config;
}
}
return originalConfig;
}
}
@@ -21,7 +21,9 @@ import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthenticator;
import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.RegistrationResponse;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
@@ -51,11 +53,18 @@ public class PolicyEnforcer {
private final AuthzClient authzClient;
private final PolicyEnforcerConfig enforcerConfig;
private final Map<String, PathConfig> paths;
private final PathMatcher pathMatcher;
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
this.deployment = deployment;
this.enforcerConfig = adapterConfig.getPolicyEnforcerConfig();
this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()));
this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()), new ClientAuthenticator() {
@Override
public void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders) {
ClientCredentialsProviderUtils.setClientCredentials(PolicyEnforcer.this.deployment, requestHeaders, requestParams);
}
});
this.pathMatcher = new PathMatcher(this.authzClient);
this.paths = configurePaths(this.authzClient.protection().resource(), this.enforcerConfig);
if (LOGGER.isDebugEnabled()) {
@@ -218,7 +227,14 @@ public class PolicyEnforcer {
pathConfig.setId(resourceDescription.getId());
pathConfig.setName(resourceDescription.getName());
pathConfig.setPath(resourceDescription.getUri());
String uri = resourceDescription.getUri();
if (uri == null || "".equals(uri.trim())) {
throw new RuntimeException("Failed to configure paths. Resource [" + resourceDescription.getName() + "] has an invalid or empty URI [" + uri + "].");
}
pathConfig.setPath(uri);
List<String> scopeNames = new ArrayList<>();
@@ -231,4 +247,8 @@ public class PolicyEnforcer {
return pathConfig;
}
public PathMatcher getPathMatcher() {
return pathMatcher;
}
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -3
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -88,7 +88,6 @@
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
@@ -104,7 +103,6 @@ projects that depend on this project.-->
<dependency>
<groupId>org.jboss.msc</groupId>
<artifactId>jboss-msc</artifactId>
<version>1.0.2.GA</version>
</dependency>
<dependency>
+13 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
@@ -30,6 +30,18 @@
<artifactId>keycloak-as7-integration-pom</artifactId>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-parent</artifactId>
<version>${jboss.as.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>as7-adapter-spi</module>
<module>as7-adapter</module>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -106,6 +106,8 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
public abstract AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment);
public abstract JettyUserSessionManagement createSessionManagement(Request request);
public void logoutCurrent(Request request) {
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext) request.getAttribute(AdapterDeploymentContext.class.getName());
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
@@ -287,7 +289,7 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
log.debug("*** deployment isn't configured return false");
return Authentication.UNAUTHENTICATED;
}
PreAuthActionsHandler handler = new PreAuthActionsHandler(new JettyUserSessionManagement(request.getSessionManager()), deploymentContext, facade);
PreAuthActionsHandler handler = new PreAuthActionsHandler(createSessionManagement(request), deploymentContext, facade);
if (handler.handleRequest()) {
return Authentication.SEND_SUCCESS;
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,40 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.SessionManager;
import org.keycloak.adapters.jetty.spi.JettySessionManager;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty81SessionManager implements JettySessionManager {
protected SessionManager sessionManager;
public Jetty81SessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
@Override
public HttpSession getHttpSession(String id) {
return sessionManager.getHttpSession(id);
}
}
@@ -25,6 +25,7 @@ import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import javax.servlet.ServletRequest;
@@ -44,6 +45,11 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
public JettyUserSessionManagement createSessionManagement(Request request) {
return new JettyUserSessionManagement(new Jetty81SessionManager(request.getSessionManager()));
}
@Override
protected Request resolveRequest(ServletRequest req) {
return (req instanceof Request)?(Request)req: AbstractHttpConnection.getCurrentConnection().getRequest();
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,40 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.SessionManager;
import org.keycloak.adapters.jetty.spi.JettySessionManager;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty91SessionManager implements JettySessionManager {
protected SessionManager sessionManager;
public Jetty91SessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
@Override
public HttpSession getHttpSession(String id) {
return sessionManager.getHttpSession(id);
}
}
@@ -27,6 +27,7 @@ import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import javax.servlet.ServletRequest;
@@ -46,6 +47,11 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
public JettyUserSessionManagement createSessionManagement(Request request) {
return new JettyUserSessionManagement(new Jetty91SessionManager(request.getSessionManager()));
}
@Override
protected Request resolveRequest(ServletRequest req) {
return (req instanceof Request) ? (Request)req : HttpChannel.getCurrentHttpChannel().getRequest();
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,40 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.SessionManager;
import org.keycloak.adapters.jetty.spi.JettySessionManager;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty92SessionManager implements JettySessionManager {
protected SessionManager sessionManager;
public Jetty92SessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
@Override
public HttpSession getHttpSession(String id) {
return sessionManager.getHttpSession(id);
}
}
@@ -27,6 +27,7 @@ import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import javax.servlet.ServletRequest;
@@ -61,6 +62,11 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
public JettyUserSessionManagement createSessionManagement(Request request) {
return new JettyUserSessionManagement(new Jetty92SessionManager(request.getSessionManager()));
}
@Override
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,40 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.SessionManager;
import org.keycloak.adapters.jetty.spi.JettySessionManager;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty93SessionManager implements JettySessionManager {
protected SessionManager sessionManager;
public Jetty93SessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
@Override
public HttpSession getHttpSession(String id) {
return sessionManager.getHttpSession(id);
}
}
@@ -26,6 +26,7 @@ import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import javax.servlet.ServletRequest;
@@ -60,6 +61,11 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
public JettyUserSessionManagement createSessionManagement(Request request) {
return new JettyUserSessionManagement(new Jetty93SessionManager(request.getSessionManager()));
}
@Override
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
+156
View File
@@ -0,0 +1,156 @@
<?xml version="1.0"?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-jetty94-adapter</artifactId>
<name>Keycloak Jetty 9.4.x Integration</name>
<properties>
<jetty9.version>9.4.2.v20170220</jetty9.version>
<keycloak.osgi.export>
org.keycloak.adapters.jetty.*
</keycloak.osgi.export>
<keycloak.osgi.import>
org.eclipse.jetty.*;resolution:=optional,
javax.servlet.*;version="[3.0,4)";resolution:=optional,
org.keycloak.*;version="${project.version}",
*;resolution:=optional
</keycloak.osgi.import>
</properties>
<description />
<dependencies>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,47 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.Request;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.spi.HttpFacade;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty94RequestAuthenticator extends JettyRequestAuthenticator {
public Jetty94RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) {
super(facade, deployment, tokenStore, sslRedirectPort, request);
}
@Override
protected String changeHttpSessionId(boolean create) {
Request request = this.request;
HttpSession session = request.getSession(false);
if (session == null) {
return request.getSession(true).getId();
}
if (!deployment.isTurnOffChangeSessionIdOnLogin()) return request.changeSessionId();
else return session.getId();
}
}
@@ -0,0 +1,40 @@
/*
* 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.jetty;
import org.eclipse.jetty.server.session.SessionHandler;
import org.keycloak.adapters.jetty.spi.JettySessionManager;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Jetty94SessionManager implements JettySessionManager {
protected SessionHandler sessionHandler;
public Jetty94SessionManager(SessionHandler sessionHandler) {
this.sessionHandler = sessionHandler;
}
@Override
public HttpSession getHttpSession(String id) {
return sessionHandler.getHttpSession(id);
}
}
@@ -0,0 +1,111 @@
/*
* 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.jetty;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.adapters.spi.AdapterSessionStore;
import org.keycloak.common.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JettyAdapterSessionStore implements AdapterSessionStore {
public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
protected Request myRequest;
public JettyAdapterSessionStore(Request request) {
this.myRequest = request; // for IDE/compilation purposes
}
protected MultiMap<String> extractFormParameters(Request base_request) {
MultiMap<String> formParameters = new MultiMap<String>();
base_request.extractFormParameters(formParameters);
return formParameters;
}
protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
base_request.setContentParameters(j_post);
}
public boolean restoreRequest() {
HttpSession session = myRequest.getSession(false);
if (session == null) return false;
synchronized (session) {
String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
if (j_uri != null) {
// check if the request is for the same url as the original and restore
// params if it was a post
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
if (j_uri.equals(buf.toString())) {
String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
myRequest.setMethod(method);
MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
if (j_post != null) {
myRequest.setContentType("application/x-www-form-urlencoded");
MultiMap<String> map = new MultiMap<String>();
for (String key : j_post.keySet()) {
for (String val : j_post.getList(key)) {
map.add(key, val);
}
}
restoreFormParameters(map, myRequest);
}
session.removeAttribute(FormAuthenticator.__J_URI);
session.removeAttribute(JettyHttpFacade.__J_METHOD);
session.removeAttribute(FormAuthenticator.__J_POST);
}
return true;
}
}
return false;
}
public void saveRequest() {
// remember the current URI
HttpSession session = myRequest.getSession();
synchronized (session) {
// But only if it is not set already, or we save every uri that leads to a login form redirect
if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
StringBuffer buf = myRequest.getRequestURL();
if (myRequest.getQueryString() != null)
buf.append("?").append(myRequest.getQueryString());
session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
MultiMap<String> formParameters = extractFormParameters(myRequest);
MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
for (String key : formParameters.keySet()) {
for (Object value : formParameters.getValues(key)) {
map.add(key, (String) value);
}
}
session.setAttribute(CACHED_FORM_PARAMETERS, map);
}
}
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.jetty;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
import javax.servlet.ServletRequest;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticator {
public KeycloakJettyAuthenticator() {
super();
}
@Override
protected Request resolveRequest(ServletRequest req) {
return Request.getBaseRequest(req);
}
@Override
protected Authentication createAuthentication(UserIdentity userIdentity, final Request request) {
return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
@Override
public void logout() {
logoutCurrent(request);
}
};
}
@Override
public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
}
@Override
public JettyUserSessionManagement createSessionManagement(Request request) {
return new JettyUserSessionManagement(new Jetty94SessionManager(request.getSessionHandler()));
}
@Override
protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
return new Jetty94RequestAuthenticator(facade, deployment, tokenStore, -1, request);
}
}
+16 -2
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
@@ -33,8 +33,22 @@
<modules>
<module>jetty-core</module>
<module>jetty8.1</module>
<module>jetty9.1</module>
<module>jetty9.2</module>
<module>jetty9.3</module>
</modules>
<profiles>
<profile>
<id>community</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<modules>
<module>jetty9.1</module>
<module>jetty9.4</module>
</modules>
</profile>
</profiles>
</project>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright 2017 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.
*/
declare module KeycloakModule {
export interface Promise {
success(callback: Function): Promise;
error(callback: Function): Promise;
}
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;
}
export interface LoginOptions {
redirectUri?: string;
prompt?: string;
maxAge?: number;
loginHint?: string;
action?: string;
locale?: string;
}
export interface RedirectUriOptions {
redirectUri?: string;
}
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;
realm: string;
clientId: string;
authServerUrl: 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;
onReady: Function;
onAuthSuccess: Function;
onAuthError: Function;
onAuthRefreshSuccess: Function;
onAuthRefreshError: Function;
onAuthLogout: Function;
onTokenExpired: Function;
}
}
declare var Keycloak: {
new(config?: any): KeycloakModule.KeycloakClient;
};
@@ -157,7 +157,7 @@
processCallback(callback, initPromise);
return;
} else if (initOptions) {
if (initOptions.refreshToken) {
if (initOptions.token && initOptions.refreshToken) {
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
if (loginIframe.enable) {
@@ -832,11 +832,16 @@
document.body.appendChild(iframe);
var messageCallback = function(event) {
if (event.origin !== loginIframe.iframeOrigin) {
if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
return;
}
if (event.data != "unchanged") {
if (!(event.data == 'unchanged' || event.data == 'changed' || event.data == 'error')) {
return;
}
if (event.data != 'unchanged') {
kc.clearToken();
}
@@ -844,7 +849,7 @@
for (var i = callbacks.length - 1; i >= 0; --i) {
var promise = callbacks[i];
if (event.data == "unchanged") {
if (event.data == 'unchanged') {
promise.setSuccess();
} else {
promise.setError();
@@ -1223,7 +1228,7 @@
break;
default:
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + encodeURIComponent(queryParams[param]);
}
break;
}
@@ -1,49 +0,0 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<script>
function getCookie(cname)
{
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++)
{
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return null;
}
function receiveMessage(event)
{
if (event.origin !== "ORIGIN") {
console.log(event.origin + " does not match built origin");
return;
}
var data = JSON.parse(event.data);
data.loggedIn = false;
var cookie = getCookie('KEYCLOAK_SESSION');
if (cookie) {
data.loggedIn = true;
data.session = cookie;
}
event.source.postMessage(JSON.stringify(data),
event.origin);
}
window.addEventListener("message", receiveMessage, false);
</script>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+3 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
@@ -41,9 +41,11 @@
<module>servlet-filter</module>
<module>servlet-oauth-client</module>
<module>spring-boot</module>
<module>spring-boot-container-bundle</module>
<module>spring-security</module>
<module>tomcat</module>
<module>undertow</module>
<module>wildfly</module>
<module>wildfly-elytron</module>
</modules>
</project>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -53,6 +53,9 @@ import java.util.regex.Pattern;
* @version $Revision: 1 $
*/
public class KeycloakOIDCFilter implements Filter {
public static final String SKIP_PATTERN_PARAM = "keycloak.config.skipPattern";
protected AdapterDeploymentContext deploymentContext;
protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
protected NodesRegistrationManagement nodesRegistrationManagement;
@@ -63,7 +66,7 @@ public class KeycloakOIDCFilter implements Filter {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
String skipPatternDefinition = filterConfig.getInitParameter("keycloak.config.skipPattern");
String skipPatternDefinition = filterConfig.getInitParameter(SKIP_PATTERN_PARAM);
if (skipPatternDefinition != null) {
skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -41,12 +41,60 @@ import java.io.InputStream;
import java.net.URI;
import java.util.List;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Base64Url;
import java.security.MessageDigest;
import java.security.SecureRandom;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
// https://tools.ietf.org/html/rfc7636#section-4
private String codeVerifier;
private String codeChallenge;
private String codeChallengeMethod = OAuth2Constants.PKCE_METHOD_S256;
private static Logger logger = Logger.getLogger(ServletOAuthClient.class);
public static String generateSecret() {
return generateSecret(32);
}
public static String generateSecret(int bytes) {
byte[] buf = new byte[bytes];
new SecureRandom().nextBytes(buf);
return Base64Url.encode(buf);
}
private void setCodeVerifier() {
codeVerifier = generateSecret();
logger.debugf("Generated codeVerifier = %s", codeVerifier);
return;
}
private void setCodeChallenge() {
try {
if (codeChallengeMethod.equals(OAuth2Constants.PKCE_METHOD_S256)) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(codeVerifier.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : md.digest()) {
String hex = String.format("%02x", b);
sb.append(hex);
}
codeChallenge = Base64Url.encode(sb.toString().getBytes());
} else {
codeChallenge = Base64Url.encode(codeVerifier.getBytes());
}
logger.debugf("Encode codeChallenge = %s, codeChallengeMethod = %s", codeChallenge, codeChallengeMethod);
} catch (Exception e) {
logger.info("PKCE client side unknown hash algorithm");
codeChallenge = Base64Url.encode(codeVerifier.getBytes());
}
}
/**
* closes client
*/
@@ -57,7 +105,15 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
private AccessTokenResponse resolveBearerToken(HttpServletRequest request, String redirectUri, String code) throws IOException, ServerRequest.HttpFailure {
// Don't send sessionId in oauth clients for now
KeycloakDeployment resolvedDeployment = resolveDeployment(getDeployment(), request);
return ServerRequest.invokeAccessCodeToToken(resolvedDeployment, code, redirectUri, null);
// https://tools.ietf.org/html/rfc7636#section-4
if (codeVerifier != null) {
logger.debugf("Before sending Token Request, codeVerifier = %s", codeVerifier);
return ServerRequest.invokeAccessCodeToToken(resolvedDeployment, code, redirectUri, null, codeVerifier);
} else {
logger.debug("Before sending Token Request without codeVerifier");
return ServerRequest.invokeAccessCodeToToken(resolvedDeployment, code, redirectUri, null);
}
}
/**
@@ -94,6 +150,12 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
String authUrl = resolvedDeployment.getAuthUrl().clone().build().toString();
String scopeParam = TokenUtil.attachOIDCScope(scope);
// https://tools.ietf.org/html/rfc7636#section-4
if (resolvedDeployment.isPkce()) {
setCodeVerifier();
setCodeChallenge();
}
KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(authUrl)
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, getClientId())
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty93-adapter</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.keycloak:keycloak-tomcat8-adapter</include>
<include>org.keycloak:keycloak-undertow-adapter</include>
<include>org.keycloak:keycloak-jetty93-adapter</include>
<include>org.keycloak:keycloak-tomcat-core-adapter</include>
<include>org.keycloak:keycloak-tomcat-adapter-spi</include>
<include>org.keycloak:keycloak-undertow-adapter</include>
<include>org.keycloak:keycloak-undertow-adapter-spi</include>
<include>org.keycloak:keycloak-jetty-core</include>
<include>org.keycloak:keycloak-jetty-adapter-spi</include>
</includes>
</artifactSet>
<createSourcesJar>true</createSourcesJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
+36 -44
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -31,7 +31,7 @@
<description/>
<properties>
<spring-boot.version>1.2.1.RELEASE</spring-boot.version>
<spring-boot.version>1.3.0.RELEASE</spring-boot.version>
</properties>
<dependencies>
@@ -43,74 +43,67 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>spring-boot-container-bundle</artifactId>
<version>${project.version}</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty92-adapter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty9.version}</version>
<scope>provided</scope>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
@@ -118,11 +111,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -60,7 +60,7 @@ import java.util.Set;
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(KeycloakSpringBootProperties.class)
public class KeycloakSpringBootConfiguration {
public class KeycloakAutoConfiguration {
private KeycloakSpringBootProperties keycloakProperties;
@@ -70,6 +70,7 @@ public class KeycloakSpringBootConfiguration {
KeycloakSpringBootConfigResolver.setAdapterConfig(keycloakProperties);
}
@Bean
public EmbeddedServletContainerCustomizer getKeycloakContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@@ -141,10 +142,10 @@ public class KeycloakSpringBootConfiguration {
List<io.undertow.servlet.api.SecurityConstraint> undertowSecurityConstraints = new ArrayList<io.undertow.servlet.api.SecurityConstraint>();
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
undertowSecurityConstraint.addRolesAllowed(constraintDefinition.getAuthRoles());
io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
undertowSecurityConstraint.addRolesAllowed(collectionDefinition.getAuthRoles());
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
WebResourceCollection webResourceCollection = new WebResourceCollection();
webResourceCollection.addHttpMethods(collectionDefinition.getMethods());
@@ -153,8 +154,9 @@ public class KeycloakSpringBootConfiguration {
undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
undertowSecurityConstraints.add(undertowSecurityConstraint);
}
undertowSecurityConstraints.add(undertowSecurityConstraint);
}
return undertowSecurityConstraints;
}
@@ -174,42 +176,70 @@ public class KeycloakSpringBootConfiguration {
KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator();
keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver());
/* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example
on how to map servlet spec to Constraints */
List<ConstraintMapping> jettyConstraintMappings = new ArrayList<ConstraintMapping>();
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition
.getSecurityCollections()) {
// securityCollection matches servlet spec's web-resource-collection
Constraint jettyConstraint = new Constraint();
if (constraintDefinition.getAuthRoles().size() > 0) {
jettyConstraint.setAuthenticate(true);
jettyConstraint.setRoles(constraintDefinition.getAuthRoles().toArray(new String[0]));
}
jettyConstraint.setName(securityCollectionDefinition.getName());
jettyConstraint.setAuthenticate(true);
if (securityCollectionDefinition.getName() != null) {
jettyConstraint.setName(securityCollectionDefinition.getName());
// according to the servlet spec each security-constraint has at least one URL pattern
for(String pattern : securityCollectionDefinition.getPatterns()) {
/* the following code is asymmetric as Jetty's ConstraintMapping accepts only one allowed HTTP method,
but multiple omitted methods. Therefore we add one ConstraintMapping for each allowed
mapping but only one mapping in the cases of omitted methods or no methods.
*/
if (securityCollectionDefinition.getMethods().size() > 0) {
// according to the servlet spec we have either methods ...
for(String method : securityCollectionDefinition.getMethods()) {
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
jettyConstraintMapping.setMethod(method);
}
} else if (securityCollectionDefinition.getOmittedMethods().size() > 0){
// ... omitted methods ...
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
jettyConstraintMapping.setMethodOmissions(
securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
} else {
// ... or no methods at all
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
jettyConstraintMappings.add(jettyConstraintMapping);
jettyConstraintMapping.setConstraint(jettyConstraint);
jettyConstraintMapping.setPathSpec(pattern);
}
}
jettyConstraint.setRoles(securityCollectionDefinition.getAuthRoles().toArray(new String[0]));
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
if (securityCollectionDefinition.getPatterns().size() > 0) {
//First pattern wins
jettyConstraintMapping.setPathSpec(securityCollectionDefinition.getPatterns().get(0));
jettyConstraintMapping.setConstraint(jettyConstraint);
}
if (securityCollectionDefinition.getMethods().size() > 0) {
//First method wins
jettyConstraintMapping.setMethod(securityCollectionDefinition.getMethods().get(0));
}
jettyConstraintMapping.setMethodOmissions(
securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
jettyConstraintMappings.add(jettyConstraintMapping);
}
}
WebAppContext webAppContext = server.getBean(WebAppContext.class);
//if not found as registered bean let's try the handler
if(webAppContext==null){
webAppContext = (WebAppContext) server.getHandler();
}
ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
securityHandler.setConstraintMappings(jettyConstraintMappings);
@@ -235,12 +265,10 @@ public class KeycloakSpringBootConfiguration {
Set<String> authRoles = new HashSet<String>();
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
for (String authRole : collection.getAuthRoles()) {
if (!authRoles.contains(authRole)) {
context.addSecurityRole(authRole);
authRoles.add(authRole);
}
for (String authRole : constraint.getAuthRoles()) {
if (!authRoles.contains(authRole)) {
context.addSecurityRole(authRole);
authRoles.add(authRole);
}
}
}
@@ -248,6 +276,10 @@ public class KeycloakSpringBootConfiguration {
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
SecurityConstraint tomcatConstraint = new SecurityConstraint();
for (String authRole : constraint.getAuthRoles()) {
tomcatConstraint.addAuthRole(authRole);
}
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
SecurityCollection tomcatSecCollection = new SecurityCollection();
@@ -258,10 +290,6 @@ public class KeycloakSpringBootConfiguration {
tomcatSecCollection.setDescription(collection.getDescription());
}
for (String authRole : collection.getAuthRoles()) {
tomcatConstraint.addAuthRole(authRole);
}
for (String pattern : collection.getPatterns()) {
tomcatSecCollection.addPattern(pattern);
}
@@ -38,10 +38,25 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
return config;
}
/**
* To provide Java EE security constraints
*/
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
/**
* This matches security-constraint of the servlet spec
*/
@ConfigurationProperties()
public static class SecurityConstraint {
/**
* A list of security collections
*/
private List<SecurityCollection> securityCollections = new ArrayList<SecurityCollection>();
private List<String> authRoles = new ArrayList<String>();
public List<String> getAuthRoles() {
return authRoles;
}
public List<SecurityCollection> getSecurityCollections() {
return securityCollections;
@@ -50,20 +65,39 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
public void setSecurityCollections(List<SecurityCollection> securityCollections) {
this.securityCollections = securityCollections;
}
public void setAuthRoles(List<String> authRoles) {
this.authRoles = authRoles;
}
}
/**
* This matches web-resource-collection of the servlet spec
*/
@ConfigurationProperties()
public static class SecurityCollection {
/**
* The name of your security constraint
*/
private String name;
/**
* The description of your security collection
*/
private String description;
private List<String> authRoles = new ArrayList<String>();
/**
* A list of URL patterns that should match to apply the security collection
*/
private List<String> patterns = new ArrayList<String>();
/**
* A list of HTTP methods that applies for this security collection
*/
private List<String> methods = new ArrayList<String>();
/**
* A list of HTTP methods that will be omitted for this security collection
*/
private List<String> omittedMethods = new ArrayList<String>();
public List<String> getAuthRoles() {
return authRoles;
}
public List<String> getPatterns() {
return patterns;
}
@@ -92,10 +126,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
this.description = description;
}
public void setAuthRoles(List<String> authRoles) {
this.authRoles = authRoles;
}
public void setPatterns(List<String> patterns) {
this.patterns = patterns;
}
@@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.keycloak.adapters.springboot.KeycloakSpringBootConfiguration
org.keycloak.adapters.springboot.KeycloakAutoConfiguration
+3 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -59,12 +59,14 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
<optional>true</optional>
<scope>compile</scope>
</dependency>
<dependency>
+16 -3
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Tomcat Integration</name>
@@ -32,8 +32,21 @@
<modules>
<module>tomcat-core</module>
<module>tomcat6</module>
<module>tomcat7</module>
<module>tomcat8</module>
</modules>
<profiles>
<profile>
<id>community</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<modules>
<module>tomcat6</module>
<module>tomcat7</module>
</modules>
</profile>
</profiles>
</project>
+1 -3
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -29,8 +29,6 @@
<artifactId>keycloak-tomcat-core-adapter</artifactId>
<name>Keycloak Tomcat Core Integration</name>
<properties>
<!-- <tomcat.version>8.0.14</tomcat.version> -->
<!-- <tomcat.version>7.0.52</tomcat.version> -->
<tomcat.version>6.0.41</tomcat.version>
</properties>
<description />
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+99
View File
@@ -0,0 +1,99 @@
<?xml version="1.0"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-wildfly-elytron-oidc-adapter</artifactId>
<name>Keycloak Wildfly Elytron OIDC Adapter</name>
<description/>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.wildfly.common</groupId>
<artifactId>wildfly-common</artifactId>
<version>1.2.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly.security.elytron-web</groupId>
<artifactId>undertow-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-spi</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,103 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.wildfly.security.auth.server.SecurityIdentity;
import javax.security.auth.callback.CallbackHandler;
import java.security.Principal;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ElytronAccount implements OidcKeycloakAccount {
protected static Logger log = Logger.getLogger(ElytronAccount.class);
private final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal;
public ElytronAccount(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
this.principal = principal;
}
@Override
public RefreshableKeycloakSecurityContext getKeycloakSecurityContext() {
return principal.getKeycloakSecurityContext();
}
@Override
public Principal getPrincipal() {
return principal;
}
@Override
public Set<String> getRoles() {
Set<String> roles = new HashSet<>();
return roles;
}
void setCurrentRequestInfo(KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
principal.getKeycloakSecurityContext().setCurrentRequestInfo(deployment, tokenStore);
}
public boolean checkActive() {
RefreshableKeycloakSecurityContext session = getKeycloakSecurityContext();
if (session.isActive() && !session.getDeployment().isAlwaysRefreshToken()) {
log.debug("session is active");
return true;
}
log.debug("session not active");
return false;
}
boolean tryRefresh(CallbackHandler callbackHandler) {
log.debug("Trying to refresh");
RefreshableKeycloakSecurityContext securityContext = getKeycloakSecurityContext();
if (securityContext == null) {
log.debug("No security context. Aborting refresh.");
}
if (securityContext.refreshExpiredToken(false)) {
SecurityIdentity securityIdentity = SecurityIdentityUtil.authorize(callbackHandler, principal);
if (securityIdentity != null) {
log.debug("refresh succeeded");
return true;
}
return false;
}
return checkActive();
}
}
@@ -0,0 +1,164 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import java.security.Principal;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.CookieTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.Scope;
import javax.security.auth.callback.CallbackHandler;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ElytronCookieTokenStore implements ElytronTokeStore {
protected static Logger log = Logger.getLogger(ElytronCookieTokenStore.class);
private final ElytronHttpFacade httpFacade;
private final CallbackHandler callbackHandler;
public ElytronCookieTokenStore(ElytronHttpFacade httpFacade, CallbackHandler callbackHandler) {
this.httpFacade = httpFacade;
this.callbackHandler = callbackHandler;
}
@Override
public void checkCurrentToken() {
KeycloakDeployment deployment = httpFacade.getDeployment();
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = CookieTokenStore.getPrincipalFromCookie(deployment, httpFacade, this);
if (principal == null) {
return;
}
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
if (securityContext.isActive() && !securityContext.getDeployment().isAlwaysRefreshToken()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
// not be updated
boolean success = securityContext.refreshExpiredToken(false);
if (success && securityContext.isActive()) return;
saveAccountInfo(new ElytronAccount(principal));
}
@Override
public boolean isCached(RequestAuthenticator authenticator) {
KeycloakDeployment deployment = httpFacade.getDeployment();
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = CookieTokenStore.getPrincipalFromCookie(deployment, httpFacade, this);
if (principal == null) {
log.debug("Account was not in cookie or was invalid, returning null");
return false;
}
ElytronAccount account = new ElytronAccount(principal);
if (!deployment.getRealm().equals(account.getKeycloakSecurityContext().getRealm())) {
log.debug("Account in session belongs to a different realm than for this request.");
return false;
}
boolean active = account.checkActive();
if (!active) {
active = account.tryRefresh(this.callbackHandler);
}
if (active) {
log.debug("Cached account found");
restoreRequest();
httpFacade.authenticationComplete(account, true);
return true;
} else {
log.debug("Account was not active, removing cookie and returning false");
CookieTokenStore.removeCookie(httpFacade);
return false;
}
}
@Override
public void saveAccountInfo(OidcKeycloakAccount account) {
RefreshableKeycloakSecurityContext secContext = (RefreshableKeycloakSecurityContext)account.getKeycloakSecurityContext();
CookieTokenStore.setTokenCookie(this.httpFacade.getDeployment(), this.httpFacade, secContext);
HttpScope exchange = this.httpFacade.getScope(Scope.EXCHANGE);
exchange.registerForNotification(httpServerScopes -> logout());
exchange.setAttachment(ElytronAccount.class.getName(), account);
exchange.setAttachment(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
restoreRequest();
}
@Override
public void logout() {
logout(false);
}
@Override
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
CookieTokenStore.setTokenCookie(this.httpFacade.getDeployment(), httpFacade, securityContext);
}
@Override
public void saveRequest() {
}
@Override
public boolean restoreRequest() {
return false;
}
@Override
public void logout(boolean glo) {
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = CookieTokenStore.getPrincipalFromCookie(this.httpFacade.getDeployment(), this.httpFacade, this);
if (principal == null) {
return;
}
CookieTokenStore.removeCookie(this.httpFacade);
if (glo) {
KeycloakSecurityContext ksc = (KeycloakSecurityContext) principal.getKeycloakSecurityContext();
if (ksc == null) {
return;
}
KeycloakDeployment deployment = httpFacade.getDeployment();
if (!deployment.isBearerOnly() && ksc != null && ksc instanceof RefreshableKeycloakSecurityContext) {
((RefreshableKeycloakSecurityContext) ksc).logout(deployment);
}
}
}
}
@@ -0,0 +1,394 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import org.bouncycastle.asn1.cmp.Challenge;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.LogoutError;
import org.keycloak.enums.TokenStore;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.HttpServerCookie;
import org.wildfly.security.http.HttpServerMechanismsResponder;
import org.wildfly.security.http.HttpServerRequest;
import org.wildfly.security.http.HttpServerResponse;
import org.wildfly.security.http.Scope;
import javax.security.auth.callback.CallbackHandler;
import javax.security.cert.X509Certificate;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class ElytronHttpFacade implements OIDCHttpFacade {
private final HttpServerRequest request;
private final CallbackHandler callbackHandler;
private final AdapterTokenStore tokenStore;
private final AdapterDeploymentContext deploymentContext;
private Consumer<HttpServerResponse> responseConsumer;
private ElytronAccount account;
private SecurityIdentity securityIdentity;
private boolean restored;
public ElytronHttpFacade(HttpServerRequest request, AdapterDeploymentContext deploymentContext, CallbackHandler handler) {
this.request = request;
this.deploymentContext = deploymentContext;
this.callbackHandler = handler;
this.tokenStore = createTokenStore();
this.responseConsumer = response -> {};
}
void authenticationComplete(ElytronAccount account, boolean storeToken) {
this.securityIdentity = SecurityIdentityUtil.authorize(this.callbackHandler, account.getPrincipal());
if (securityIdentity != null) {
this.account = account;
RefreshableKeycloakSecurityContext keycloakSecurityContext = account.getKeycloakSecurityContext();
account.setCurrentRequestInfo(keycloakSecurityContext.getDeployment(), this.tokenStore);
if (storeToken) {
this.tokenStore.saveAccountInfo(account);
}
}
}
void authenticationComplete() {
if (securityIdentity != null) {
this.request.authenticationComplete(response -> {
if (!restored) {
responseConsumer.accept(response);
}
}, () -> ((ElytronTokeStore) tokenStore).logout(true));
}
}
void authenticationFailed() {
this.request.authenticationFailed("Authentication Failed", response -> responseConsumer.accept(response));
}
void noAuthenticationInProgress() {
this.request.noAuthenticationInProgress();
}
void noAuthenticationInProgress(AuthChallenge challenge) {
if (challenge != null) {
challenge.challenge(this);
}
this.request.noAuthenticationInProgress(response -> responseConsumer.accept(response));
}
void authenticationInProgress() {
this.request.authenticationInProgress(response -> responseConsumer.accept(response));
}
HttpScope getScope(Scope scope) {
return request.getScope(scope);
}
HttpScope getScope(Scope scope, String id) {
return request.getScope(scope, id);
}
Collection<String> getScopeIds(Scope scope) {
return request.getScopeIds(scope);
}
AdapterTokenStore getTokenStore() {
return this.tokenStore;
}
KeycloakDeployment getDeployment() {
return deploymentContext.resolveDeployment(this);
}
private AdapterTokenStore createTokenStore() {
KeycloakDeployment deployment = getDeployment();
if (TokenStore.SESSION.equals(deployment.getTokenStore())) {
return new ElytronSessionTokenStore(this, this.callbackHandler);
} else {
return new ElytronCookieTokenStore(this, this.callbackHandler);
}
}
@Override
public Request getRequest() {
return new Request() {
@Override
public String getMethod() {
return request.getRequestMethod();
}
@Override
public String getURI() {
try {
return URLDecoder.decode(request.getRequestURI().toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Failed to decode request URI", e);
}
}
@Override
public String getRelativePath() {
return request.getRequestPath();
}
@Override
public boolean isSecure() {
return request.getRequestURI().getScheme().equals("https");
}
@Override
public String getFirstParam(String param) {
throw new RuntimeException("Not implemented.");
}
@Override
public String getQueryParamValue(String param) {
URI requestURI = request.getRequestURI();
String query = requestURI.getQuery();
if (query != null) {
String[] parameters = query.split("&");
for (String parameter : parameters) {
String[] keyValue = parameter.split("=");
if (keyValue[0].equals(param)) {
return keyValue[1];
}
}
}
return null;
}
@Override
public Cookie getCookie(final String cookieName) {
List<HttpServerCookie> cookies = request.getCookies();
if (cookies != null) {
for (HttpServerCookie cookie : cookies) {
if (cookie.getName().equals(cookieName)) {
return new Cookie(cookie.getName(), cookie.getValue(), cookie.getVersion(), cookie.getDomain(), cookie.getPath());
}
}
}
return null;
}
@Override
public String getHeader(String name) {
return request.getFirstRequestHeaderValue(name);
}
@Override
public List<String> getHeaders(String name) {
return request.getRequestHeaderValues(name);
}
@Override
public InputStream getInputStream() {
return request.getInputStream();
}
@Override
public String getRemoteAddr() {
InetSocketAddress sourceAddress = request.getSourceAddress();
if (sourceAddress == null) {
return "";
}
InetAddress address = sourceAddress.getAddress();
if (address == null) {
// this is unresolved, so we just return the host name not exactly spec, but if the name should be
// resolved then a PeerNameResolvingHandler should be used and this is probably better than just
// returning null
return sourceAddress.getHostString();
}
return address.getHostAddress();
}
@Override
public void setError(AuthenticationError error) {
request.getScope(Scope.EXCHANGE).setAttachment(AuthenticationError.class.getName(), error);
}
@Override
public void setError(LogoutError error) {
request.getScope(Scope.EXCHANGE).setAttachment(LogoutError.class.getName(), error);
}
};
}
@Override
public Response getResponse() {
return new Response() {
@Override
public void setStatus(final int status) {
responseConsumer = responseConsumer.andThen(response -> response.setStatusCode(status));
}
@Override
public void addHeader(final String name, final String value) {
responseConsumer = responseConsumer.andThen(response -> response.addResponseHeader(name, value));
}
@Override
public void setHeader(String name, String value) {
addHeader(name, value);
}
@Override
public void resetCookie(final String name, final String path) {
responseConsumer = responseConsumer.andThen(response -> setCookie(name, "", path, null, 0, false, false, response));
}
@Override
public void setCookie(final String name, final String value, final String path, final String domain, final int maxAge, final boolean secure, final boolean httpOnly) {
responseConsumer = responseConsumer.andThen(response -> setCookie(name, value, path, domain, maxAge, secure, httpOnly, response));
}
private void setCookie(final String name, final String value, final String path, final String domain, final int maxAge, final boolean secure, final boolean httpOnly, HttpServerResponse response) {
response.setResponseCookie(new HttpServerCookie() {
@Override
public String getName() {
return name;
}
@Override
public String getValue() {
return value;
}
@Override
public String getDomain() {
return domain;
}
@Override
public int getMaxAge() {
return maxAge;
}
@Override
public String getPath() {
return path;
}
@Override
public boolean isSecure() {
return secure;
}
@Override
public int getVersion() {
return 0;
}
@Override
public boolean isHttpOnly() {
return httpOnly;
}
});
}
@Override
public OutputStream getOutputStream() {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
responseConsumer = responseConsumer.andThen(new Consumer<HttpServerResponse>() {
@Override
public void accept(HttpServerResponse httpServerResponse) {
try {
httpServerResponse.getOutputStream().write(stream.toByteArray());
} catch (IOException e) {
throw new RuntimeException("Failed to write to response output stream", e);
}
}
});
return stream;
}
@Override
public void sendError(int code) {
setStatus(code);
}
@Override
public void sendError(final int code, final String message) {
responseConsumer = responseConsumer.andThen(response -> {
response.setStatusCode(code);
response.addResponseHeader("Content-Type", "text/html");
try {
response.getOutputStream().write(message.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
@Override
public void end() {
}
};
}
@Override
public X509Certificate[] getCertificateChain() {
return new X509Certificate[0];
}
@Override
public KeycloakSecurityContext getSecurityContext() {
if (account == null) {
return null;
}
return this.account.getKeycloakSecurityContext();
}
public boolean restoreRequest() {
restored = this.request.resumeRequest();
return restored;
}
public void suspendRequest() {
responseConsumer = responseConsumer.andThen(httpServerResponse -> request.suspendRequest());
}
public boolean isAuthorized() {
return this.securityIdentity != null;
}
}
@@ -0,0 +1,86 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.BearerTokenRequestAuthenticator;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OAuthRequestAuthenticator;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.AuthOutcome;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.Scope;
import javax.security.auth.callback.CallbackHandler;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ElytronRequestAuthenticator extends RequestAuthenticator {
public ElytronRequestAuthenticator(CallbackHandler callbackHandler, ElytronHttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort) {
super(facade, deployment, facade.getTokenStore(), sslRedirectPort);
}
@Override
public AuthOutcome authenticate() {
AuthOutcome authenticate = super.authenticate();
if (AuthOutcome.AUTHENTICATED.equals(authenticate)) {
if (!getElytronHttpFacade().isAuthorized()) {
return AuthOutcome.FAILED;
}
}
return authenticate;
}
@Override
protected OAuthRequestAuthenticator createOAuthAuthenticator() {
return new OAuthRequestAuthenticator(this, facade, deployment, sslRedirectPort, tokenStore);
}
@Override
protected void completeOAuthAuthentication(final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
getElytronHttpFacade().authenticationComplete(new ElytronAccount(principal), true);
}
@Override
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
getElytronHttpFacade().authenticationComplete(new ElytronAccount(principal), false);
}
@Override
protected String changeHttpSessionId(boolean create) {
HttpScope session = getElytronHttpFacade().getScope(Scope.SESSION);
if (create) {
if (!session.exists()) {
session.create();
}
}
return session != null ? session.getID() : null;
}
private ElytronHttpFacade getElytronHttpFacade() {
return (ElytronHttpFacade) facade;
}
}
@@ -0,0 +1,202 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import java.util.function.Consumer;
import javax.security.auth.callback.CallbackHandler;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OidcKeycloakAccount;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.HttpScopeNotification;
import org.wildfly.security.http.Scope;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ElytronSessionTokenStore implements ElytronTokeStore {
private static Logger log = Logger.getLogger(ElytronSessionTokenStore.class);
private final ElytronHttpFacade httpFacade;
private final CallbackHandler callbackHandler;
public ElytronSessionTokenStore(ElytronHttpFacade httpFacade, CallbackHandler callbackHandler) {
this.httpFacade = httpFacade;
this.callbackHandler = callbackHandler;
}
@Override
public void checkCurrentToken() {
HttpScope session = httpFacade.getScope(Scope.SESSION);
if (!session.exists()) return;
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) session.getAttachment(KeycloakSecurityContext.class.getName());
if (securityContext == null) return;
// just in case session got serialized
if (securityContext.getDeployment() == null) securityContext.setCurrentRequestInfo(httpFacade.getDeployment(), this);
if (securityContext.isActive() && !securityContext.getDeployment().isAlwaysRefreshToken()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
// not be updated
boolean success = securityContext.refreshExpiredToken(false);
if (success && securityContext.isActive()) return;
// Refresh failed, so user is already logged out from keycloak. Cleanup and expire our session
session.setAttachment(KeycloakSecurityContext.class.getName(), null);
session.invalidate();
}
@Override
public boolean isCached(RequestAuthenticator authenticator) {
HttpScope session = this.httpFacade.getScope(Scope.SESSION);
if (session == null) {
log.debug("session was null, returning null");
return false;
}
ElytronAccount account;
try {
account = (ElytronAccount) session.getAttachment(ElytronAccount.class.getName());
} catch (IllegalStateException e) {
log.debug("session was invalidated. Return false.");
return false;
}
if (account == null) {
log.debug("Account was not in session, returning null");
return false;
}
KeycloakDeployment deployment = httpFacade.getDeployment();
if (!deployment.getRealm().equals(account.getKeycloakSecurityContext().getRealm())) {
log.debug("Account in session belongs to a different realm than for this request.");
return false;
}
boolean active = account.checkActive();
if (!active) {
active = account.tryRefresh(this.callbackHandler);
}
if (active) {
log.debug("Cached account found");
restoreRequest();
httpFacade.authenticationComplete(account, true);
return true;
} else {
log.debug("Refresh failed. Account was not active. Returning null and invalidating Http session");
try {
session.setAttachment(KeycloakSecurityContext.class.getName(), null);
session.setAttachment(ElytronAccount.class.getName(), null);
session.invalidate();
} catch (Exception e) {
log.debug("Failed to invalidate session, might already be invalidated");
}
return false;
}
}
@Override
public void saveAccountInfo(OidcKeycloakAccount account) {
HttpScope session = this.httpFacade.getScope(Scope.SESSION);
if (!session.exists()) {
session.create();
}
session.setAttachment(ElytronAccount.class.getName(), account);
session.setAttachment(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
session.registerForNotification(httpScopeNotification -> {
if (!httpScopeNotification.isOfType(HttpScopeNotification.SessionNotificationType.UNDEPLOY)) {
logout();
}
});
HttpScope scope = this.httpFacade.getScope(Scope.EXCHANGE);
scope.setAttachment(KeycloakSecurityContext.class.getName(), account.getKeycloakSecurityContext());
}
@Override
public void logout() {
logout(false);
}
@Override
public void refreshCallback(RefreshableKeycloakSecurityContext securityContext) {
KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(AdapterUtils.getPrincipalName(this.httpFacade.getDeployment(), securityContext.getToken()), securityContext);
saveAccountInfo(new ElytronAccount(principal));
}
@Override
public void saveRequest() {
this.httpFacade.suspendRequest();
}
@Override
public boolean restoreRequest() {
return this.httpFacade.restoreRequest();
}
@Override
public void logout(boolean glo) {
HttpScope session = this.httpFacade.getScope(Scope.SESSION);
if (!session.exists()) {
return;
}
try {
if (glo) {
KeycloakSecurityContext ksc = (KeycloakSecurityContext) session.getAttachment(KeycloakSecurityContext.class.getName());
if (ksc == null) {
return;
}
KeycloakDeployment deployment = httpFacade.getDeployment();
if (!deployment.isBearerOnly() && ksc != null && ksc instanceof RefreshableKeycloakSecurityContext) {
((RefreshableKeycloakSecurityContext) ksc).logout(deployment);
}
}
session.setAttachment(KeycloakSecurityContext.class.getName(), null);
session.setAttachment(ElytronAccount.class.getName(), null);
session.invalidate();
} catch (IllegalStateException ise) {
// Session may be already logged-out in case that app has adminUrl
log.debugf("Session %s logged-out already", session.getID());
}
}
}
@@ -0,0 +1,26 @@
/*
* 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.elytron;
import org.keycloak.adapters.AdapterTokenStore;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface ElytronTokeStore extends AdapterTokenStore {
void logout(boolean glo);
}
@@ -0,0 +1,109 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.constants.AdapterConstants;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
* <p>A {@link ServletContextListener} that parses the keycloak adapter configuration and set the same configuration
* as a {@link ServletContext} attribute in order to provide to {@link KeycloakHttpServerAuthenticationMechanism} a way
* to obtain the configuration when processing requests.
*
* <p>This listener should be automatically registered to a deployment using the subsystem.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakConfigurationServletListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
String configResolverClass = servletContext.getInitParameter("keycloak.config.resolver");
KeycloakConfigResolver configResolver;
AdapterDeploymentContext deploymentContext;
if (configResolverClass != null) {
try {
configResolver = (KeycloakConfigResolver) servletContext.getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
} catch (Exception ex) {
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
} else {
InputStream is = getConfigInputStream(servletContext);
KeycloakDeployment deployment;
if (is == null) {
deployment = new KeycloakDeployment();
} else {
deployment = KeycloakDeploymentBuilder.build(is);
}
deploymentContext = new AdapterDeploymentContext(deployment);
}
servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
private InputStream getConfigInputStream(ServletContext servletContext) {
InputStream is = getJSONFromServletContext(servletContext);
if (is == null) {
String path = servletContext.getInitParameter("keycloak.config.file");
if (path == null) {
is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json");
} else {
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
return is;
}
private InputStream getJSONFromServletContext(ServletContext servletContext) {
String json = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
if (json == null) {
return null;
}
return new ByteArrayInputStream(json.getBytes());
}
}
@@ -0,0 +1,168 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AuthenticatedActionsHandler;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.PreAuthActionsHandler;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.UserSessionManagement;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpScope;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
import org.wildfly.security.http.HttpServerRequest;
import org.wildfly.security.http.Scope;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticationMechanism {
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanismFactory.class);
static final String NAME = "KEYCLOAK";
private final Map<String, ?> properties;
private final CallbackHandler callbackHandler;
private final AdapterDeploymentContext deploymentContext;
public KeycloakHttpServerAuthenticationMechanism(Map<String, ?> properties, CallbackHandler callbackHandler, AdapterDeploymentContext deploymentContext) {
this.properties = properties;
this.callbackHandler = callbackHandler;
this.deploymentContext = deploymentContext;
}
@Override
public String getMechanismName() {
return NAME;
}
@Override
public void evaluateRequest(HttpServerRequest request) throws HttpAuthenticationException {
LOGGER.debugf("Evaluating request for path [%s]", request.getRequestURI());
AdapterDeploymentContext deploymentContext = getDeploymentContext(request);
if (deploymentContext == null) {
LOGGER.debugf("Ignoring request for path [%s] from mechanism [%s]. No deployment context found.", request.getRequestURI());
request.noAuthenticationInProgress();
return;
}
ElytronHttpFacade httpFacade = new ElytronHttpFacade(request, deploymentContext, callbackHandler);
KeycloakDeployment deployment = httpFacade.getDeployment();
if (!deployment.isConfigured()) {
request.noAuthenticationInProgress();
return;
}
RequestAuthenticator authenticator = createRequestAuthenticator(request, httpFacade, deployment);
httpFacade.getTokenStore().checkCurrentToken();
if (preActions(httpFacade, deploymentContext)) {
LOGGER.debugf("Pre-actions has aborted the evaluation of [%s]", request.getRequestURI());
httpFacade.authenticationInProgress();
return;
}
AuthOutcome outcome = authenticator.authenticate();
if (AuthOutcome.AUTHENTICATED.equals(outcome)) {
if (new AuthenticatedActionsHandler(deployment, httpFacade).handledRequest()) {
httpFacade.authenticationInProgress();
} else {
httpFacade.authenticationComplete();
}
return;
}
AuthChallenge challenge = authenticator.getChallenge();
if (challenge != null) {
httpFacade.noAuthenticationInProgress(challenge);
return;
}
if (AuthOutcome.FAILED.equals(outcome)) {
httpFacade.getResponse().setStatus(403);
httpFacade.authenticationFailed();
return;
}
httpFacade.noAuthenticationInProgress();
}
private ElytronRequestAuthenticator createRequestAuthenticator(HttpServerRequest request, ElytronHttpFacade httpFacade, KeycloakDeployment deployment) {
return new ElytronRequestAuthenticator(this.callbackHandler, httpFacade, deployment, getConfidentialPort(request));
}
private AdapterDeploymentContext getDeploymentContext(HttpServerRequest request) {
if (this.deploymentContext == null) {
return (AdapterDeploymentContext) request.getScope(Scope.APPLICATION).getAttachment(AdapterDeploymentContext.class.getName());
}
return this.deploymentContext;
}
private boolean preActions(ElytronHttpFacade httpFacade, AdapterDeploymentContext deploymentContext) {
NodesRegistrationManagement nodesRegistrationManagement = new NodesRegistrationManagement();
nodesRegistrationManagement.tryRegister(httpFacade.getDeployment());
PreAuthActionsHandler preActions = new PreAuthActionsHandler(new UserSessionManagement() {
@Override
public void logoutAll() {
Collection<String> sessions = httpFacade.getScopeIds(Scope.SESSION);
logoutHttpSessions(new ArrayList<>(sessions));
}
@Override
public void logoutHttpSessions(List<String> ids) {
for (String id : ids) {
HttpScope session = httpFacade.getScope(Scope.SESSION, id);
if (session != null) {
session.invalidate();
}
}
}
}, deploymentContext, httpFacade);
return preActions.handleRequest();
}
// TODO: obtain confidential port from Elytron
private int getConfidentialPort(HttpServerRequest request) {
return 8443;
}
}
@@ -0,0 +1,67 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpServerAuthenticationMechanism;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import javax.security.auth.callback.CallbackHandler;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakHttpServerAuthenticationMechanismFactory implements HttpServerAuthenticationMechanismFactory {
private final AdapterDeploymentContext deploymentContext;
/**
* <p>Creates a new instance.
*
* <p>A default constructor is necessary in order to allow this factory to be loaded via {@link java.util.ServiceLoader}.
*/
public KeycloakHttpServerAuthenticationMechanismFactory() {
this(null);
}
public KeycloakHttpServerAuthenticationMechanismFactory(AdapterDeploymentContext deploymentContext) {
this.deploymentContext = deploymentContext;
}
@Override
public String[] getMechanismNames(Map<String, ?> properties) {
return new String[] {KeycloakHttpServerAuthenticationMechanism.NAME};
}
@Override
public HttpServerAuthenticationMechanism createAuthenticationMechanism(String mechanismName, Map<String, ?> properties, CallbackHandler callbackHandler) throws HttpAuthenticationException {
Map<String, Object> mechanismProperties = new HashMap();
mechanismProperties.putAll(properties);
if (KeycloakHttpServerAuthenticationMechanism.NAME.equals(mechanismName)) {
return new KeycloakHttpServerAuthenticationMechanism(properties, callbackHandler, this.deploymentContext);
}
return null;
}
}
@@ -0,0 +1,103 @@
/*
* 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.elytron;
import java.security.Principal;
import java.util.Set;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.wildfly.security.auth.SupportLevel;
import org.wildfly.security.auth.server.RealmIdentity;
import org.wildfly.security.auth.server.RealmUnavailableException;
import org.wildfly.security.auth.server.SecurityRealm;
import org.wildfly.security.authz.Attributes;
import org.wildfly.security.authz.AuthorizationIdentity;
import org.wildfly.security.authz.MapAttributes;
import org.wildfly.security.authz.RoleDecoder;
import org.wildfly.security.credential.Credential;
import org.wildfly.security.evidence.Evidence;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakSecurityRealm implements SecurityRealm {
@Override
public RealmIdentity getRealmIdentity(Principal principal) throws RealmUnavailableException {
if (principal instanceof KeycloakPrincipal) {
return createRealmIdentity((KeycloakPrincipal) principal);
}
return RealmIdentity.NON_EXISTENT;
}
private RealmIdentity createRealmIdentity(KeycloakPrincipal principal) {
return new RealmIdentity() {
@Override
public Principal getRealmIdentityPrincipal() {
return principal;
}
@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
@Override
public <C extends Credential> C getCredential(Class<C> credentialType) throws RealmUnavailableException {
return null;
}
@Override
public SupportLevel getEvidenceVerifySupport(Class<? extends Evidence> evidenceType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.SUPPORTED;
}
@Override
public boolean verifyEvidence(Evidence evidence) throws RealmUnavailableException {
return principal != null;
}
@Override
public boolean exists() throws RealmUnavailableException {
return principal != null;
}
@Override
public AuthorizationIdentity getAuthorizationIdentity() throws RealmUnavailableException {
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) principal.getKeycloakSecurityContext();
Attributes attributes = new MapAttributes();
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
attributes.addAll(RoleDecoder.KEY_ROLES, roles);
return AuthorizationIdentity.basicIdentity(attributes);
}
};
}
@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
@Override
public SupportLevel getEvidenceVerifySupport(Class<? extends Evidence> evidenceType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.POSSIBLY_SUPPORTED;
}
}
@@ -0,0 +1,82 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.elytron;
import java.io.IOException;
import java.security.Principal;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.wildfly.security.auth.callback.AuthenticationCompleteCallback;
import org.wildfly.security.auth.callback.EvidenceVerifyCallback;
import org.wildfly.security.auth.callback.SecurityIdentityCallback;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.evidence.Evidence;
import org.wildfly.security.http.HttpAuthenticationException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
final class SecurityIdentityUtil {
static final SecurityIdentity authorize(CallbackHandler callbackHandler, Principal principal) {
try {
EvidenceVerifyCallback evidenceVerifyCallback = new EvidenceVerifyCallback(new Evidence() {
@Override
public Principal getPrincipal() {
return principal;
}
});
callbackHandler.handle(new Callback[]{evidenceVerifyCallback});
if (evidenceVerifyCallback.isVerified()) {
AuthorizeCallback authorizeCallback = new AuthorizeCallback(null, null);
try {
callbackHandler.handle(new Callback[] {authorizeCallback});
authorizeCallback.isAuthorized();
} catch (Exception e) {
throw new HttpAuthenticationException(e);
}
SecurityIdentityCallback securityIdentityCallback = new SecurityIdentityCallback();
callbackHandler.handle(new Callback[]{AuthenticationCompleteCallback.SUCCEEDED, securityIdentityCallback});
SecurityIdentity securityIdentity = securityIdentityCallback.getSecurityIdentity();
return securityIdentity;
}
} catch (UnsupportedCallbackException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return null;
}
}
@@ -1,12 +1,13 @@
#
# Copyright 2016 Red Hat, Inc. and/or its affiliates
# and other contributors as indicated by the @author tags.
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual 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
# 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,
@@ -15,4 +16,4 @@
# limitations under the License.
#
org.keycloak.models.mongo.keycloak.adapters.MongoRealmProviderFactory
org.keycloak.adapters.elytron.KeycloakHttpServerAuthenticationMechanismFactory
+15 -2
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak WildFly Integration</name>
@@ -32,7 +32,20 @@
<modules>
<module>wildfly-adapter</module>
<module>wf8-subsystem</module>
<module>wildfly-subsystem</module>
</modules>
<profiles>
<profile>
<id>community</id>
<activation>
<property>
<name>!product</name>
</property>
</activation>
<modules>
<module>wf8-subsystem</module>
</modules>
</profile>
</profiles>
</project>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -167,7 +167,12 @@ public class SharedAttributeDefinitons {
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition AUTODETECT_BEARER_ONLY =
new SimpleAttributeDefinitionBuilder("autodetect-bearer-only", ModelType.BOOLEAN, true)
.setXmlName("autodetect-bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
@@ -193,6 +198,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
ATTRIBUTES.add(TOKEN_STORE);
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
}
/**
@@ -46,7 +46,7 @@ keycloak.realm.register-node-at-startup=Cluster setting
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.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
@@ -83,6 +83,7 @@ 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.autodetect-bearer-only=autodetect bearer-only requests
keycloak.secure-deployment.credential=Credential value
@@ -65,6 +65,7 @@
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<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:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -107,6 +108,7 @@
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<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:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -166,6 +166,12 @@ public class SharedAttributeDefinitons {
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition AUTODETECT_BEARER_ONLY =
new SimpleAttributeDefinitionBuilder("autodetect-bearer-only", ModelType.BOOLEAN, true)
.setXmlName("autodetect-bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
@@ -193,6 +199,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
ATTRIBUTES.add(TOKEN_STORE);
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
}
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
@@ -46,7 +46,7 @@ keycloak.realm.register-node-at-startup=Cluster setting
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.secure-deployment=A deployment secured by Keycloak
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
@@ -67,6 +67,7 @@ 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
keycloak.secure-deployment.enable-cors=Enable Keycloak CORS support
keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests
keycloak.secure-deployment.client-keystore=n/a
keycloak.secure-deployment.client-keystore-password=n/a
keycloak.secure-deployment.client-key-password=n/a
@@ -65,6 +65,7 @@
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<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:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
@@ -107,6 +108,7 @@
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<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:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.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>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -22,9 +22,10 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.keycloak.adapters.jbossweb.JBossWebPrincipalFactory;
import org.keycloak.adapters.saml.AbstractSamlAuthenticatorValve;
import org.keycloak.adapters.saml.SamlDeployment;
import org.keycloak.adapters.saml.*;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
import javax.servlet.http.HttpServletResponse;
@@ -71,4 +72,11 @@ public class SamlAuthenticatorValve extends AbstractSamlAuthenticatorValve {
protected GenericPrincipalFactory createPrincipalFactory() {
return new JBossWebPrincipalFactory();
}
@Override
protected void addTokenStoreUpdaters() {
context.addApplicationListenerInstance(new IdMapperUpdaterSessionListener(mapper));
setIdMapperUpdater(SessionIdMapperUpdater.EXTERNAL);
super.addTokenStoreUpdaters();
}
}
@@ -0,0 +1,111 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.jbossweb.infinispan;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.manager.EmbeddedCacheManager;
import org.jboss.logging.Logger;
/**
*
* @author hmlnarik
*/
public class InfinispanSessionCacheIdMapperUpdater {
private static final Logger LOG = Logger.getLogger(InfinispanSessionCacheIdMapperUpdater.class);
public static final String DEFAULT_CACHE_CONTAINER_JNDI_NAME = "java:jboss/infinispan/container/web";
private static final String DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheContainerJndi";
private static final String DEPLOYMENT_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.deploymentCacheName";
private static final String SSO_CACHE_NAME_PARAM_NAME = "keycloak.sessionIdMapperUpdater.infinispan.cacheName";
public static SessionIdMapperUpdater addTokenStoreUpdaters(Context context, SessionIdMapper mapper, SessionIdMapperUpdater previousIdMapperUpdater) {
boolean distributable = context.getDistributable();
if (! distributable) {
LOG.warnv("Deployment {0} does not use supported distributed session cache mechanism", context.getName());
return previousIdMapperUpdater;
}
ServletContext servletContext = context.getServletContext();
String cacheContainerLookup = (servletContext != null && servletContext.getInitParameter(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME) != null)
? servletContext.getInitParameter(DEPLOYMENT_CACHE_CONTAINER_JNDI_NAME_PARAM_NAME)
: DEFAULT_CACHE_CONTAINER_JNDI_NAME;
// the following is based on https://github.com/jbossas/jboss-as/blob/7.2.0.Final/clustering/web-infinispan/src/main/java/org/jboss/as/clustering/web/infinispan/DistributedCacheManagerFactory.java#L116-L122
String host = context.getParent() == null ? "" : context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "/ROOT";
}
boolean deploymentSessionCacheNamePreset = servletContext != null && servletContext.getInitParameter(DEPLOYMENT_CACHE_NAME_PARAM_NAME) != null;
String deploymentSessionCacheName = deploymentSessionCacheNamePreset
? servletContext.getInitParameter(DEPLOYMENT_CACHE_NAME_PARAM_NAME)
: host + contextPath;
boolean ssoCacheNamePreset = servletContext != null && servletContext.getInitParameter(SSO_CACHE_NAME_PARAM_NAME) != null;
String ssoCacheName = ssoCacheNamePreset
? servletContext.getInitParameter(SSO_CACHE_NAME_PARAM_NAME)
: deploymentSessionCacheName + ".ssoCache";
try {
EmbeddedCacheManager cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup);
Configuration ssoCacheConfiguration = cacheManager.getCacheConfiguration(ssoCacheName);
if (ssoCacheConfiguration == null) {
Configuration cacheConfiguration = cacheManager.getCacheConfiguration(deploymentSessionCacheName);
if (cacheConfiguration == null) {
LOG.debugv("Using default cache container configuration for SSO cache. lookup={0}, looked up configuration of cache={1}", cacheContainerLookup, deploymentSessionCacheName);
ssoCacheConfiguration = cacheManager.getDefaultCacheConfiguration();
} else {
LOG.debugv("Using distributed HTTP session cache configuration for SSO cache. lookup={0}, configuration taken from cache={1}", cacheContainerLookup, deploymentSessionCacheName);
ssoCacheConfiguration = cacheConfiguration;
cacheManager.defineConfiguration(ssoCacheName, ssoCacheConfiguration);
}
} else {
LOG.debugv("Using custom configuration for SSO cache. lookup={0}, cache name={1}", cacheContainerLookup, ssoCacheName);
}
CacheMode ssoCacheMode = ssoCacheConfiguration.clustering().cacheMode();
if (ssoCacheMode != CacheMode.REPL_ASYNC && ssoCacheMode != CacheMode.REPL_SYNC) {
LOG.warnv("SSO cache mode is {0}, it is recommended to use replicated mode instead", ssoCacheConfiguration.clustering().cacheModeString());
}
Cache<String, String[]> ssoCache = cacheManager.getCache(ssoCacheName, true);
ssoCache.addListener(new SsoSessionCacheListener(mapper));
LOG.debugv("Added distributed SSO session cache, lookup={0}, cache name={1}", cacheContainerLookup, deploymentSessionCacheName);
SsoCacheSessionIdMapperUpdater updater = new SsoCacheSessionIdMapperUpdater(ssoCache, previousIdMapperUpdater);
return updater;
} catch (NamingException ex) {
LOG.warnv("Failed to obtain distributed session cache container, lookup={0}", cacheContainerLookup);
return previousIdMapperUpdater;
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.jbossweb.infinispan;
import org.keycloak.adapters.spi.SessionIdMapper;
import org.keycloak.adapters.spi.SessionIdMapperUpdater;
import org.infinispan.Cache;
/**
*
* @author hmlnarik
*/
public class SsoCacheSessionIdMapperUpdater implements SessionIdMapperUpdater {
private final SessionIdMapperUpdater delegate;
/**
* Cache where key is a HTTP session ID, and value is a pair (user session ID, principal name) of Strings.
*/
private final Cache<String, String[]> httpSessionToSsoCache;
public SsoCacheSessionIdMapperUpdater(Cache<String, String[]> httpSessionToSsoCache, SessionIdMapperUpdater previousIdMapperUpdater) {
this.delegate = previousIdMapperUpdater;
this.httpSessionToSsoCache = httpSessionToSsoCache;
}
// SessionIdMapperUpdater methods
@Override
public void clear(SessionIdMapper idMapper) {
httpSessionToSsoCache.clear();
this.delegate.clear(idMapper);
}
@Override
public void map(SessionIdMapper idMapper, String sso, String principal, String httpSessionId) {
httpSessionToSsoCache.put(httpSessionId, new String[] {sso, principal});
this.delegate.map(idMapper, sso, principal, httpSessionId);
}
@Override
public void removeSession(SessionIdMapper idMapper, String httpSessionId) {
httpSessionToSsoCache.remove(httpSessionId);
this.delegate.removeSession(idMapper, httpSessionId);
}
}
@@ -0,0 +1,156 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.adapters.saml.jbossweb.infinispan;
import org.keycloak.adapters.spi.SessionIdMapper;
import java.util.*;
import java.util.concurrent.*;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.*;
import org.infinispan.notifications.cachelistener.event.*;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted;
import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped;
import org.infinispan.notifications.cachemanagerlistener.event.CacheStartedEvent;
import org.infinispan.notifications.cachemanagerlistener.event.CacheStoppedEvent;
import org.infinispan.transaction.xa.GlobalTransaction;
import org.jboss.logging.Logger;
/**
*
* @author hmlnarik
*/
@Listener
public class SsoSessionCacheListener {
private static final Logger LOG = Logger.getLogger(SsoSessionCacheListener.class);
private final ConcurrentMap<GlobalTransaction, Queue<Event>> map = new ConcurrentHashMap<>();
private final SessionIdMapper idMapper;
private ExecutorService executor = Executors.newSingleThreadExecutor();
public SsoSessionCacheListener(SessionIdMapper idMapper) {
this.idMapper = idMapper;
}
@TransactionRegistered
public void startTransaction(TransactionRegisteredEvent event) {
map.put(event.getGlobalTransaction(), new ConcurrentLinkedQueue<Event>());
}
@CacheStarted
public void cacheStarted(CacheStartedEvent event) {
this.executor = Executors.newSingleThreadExecutor();
}
@CacheStopped
public void cacheStopped(CacheStoppedEvent event) {
this.executor.shutdownNow();
}
@CacheEntryCreated
@CacheEntryRemoved
@CacheEntryModified
public void addEvent(TransactionalEvent event) {
if (event.isPre() == false) {
map.get(event.getGlobalTransaction()).add(event);
}
}
@TransactionCompleted
public void endTransaction(TransactionCompletedEvent event) {
Queue<Event> events = map.remove(event.getGlobalTransaction());
if (events == null || ! event.isTransactionSuccessful()) {
return;
}
if (event.isOriginLocal()) {
// Local events are processed by local HTTP session listener
return;
}
for (final Event e : events) {
switch (e.getType()) {
case CACHE_ENTRY_CREATED:
this.executor.submit(new Runnable() {
@Override public void run() {
cacheEntryCreated((CacheEntryCreatedEvent) e);
}
});
break;
case CACHE_ENTRY_MODIFIED:
this.executor.submit(new Runnable() {
@Override public void run() {
cacheEntryModified((CacheEntryModifiedEvent) e);
}
});
break;
case CACHE_ENTRY_REMOVED:
this.executor.submit(new Runnable() {
@Override public void run() {
cacheEntryRemoved((CacheEntryRemovedEvent) e);
}
});
break;
}
}
}
private void cacheEntryCreated(CacheEntryCreatedEvent event) {
if (! (event.getKey() instanceof String) || ! (event.getValue() instanceof String[])) {
return;
}
String httpSessionId = (String) event.getKey();
String[] value = (String[]) event.getValue();
String ssoId = value[0];
String principal = value[1];
LOG.tracev("cacheEntryCreated {0}:{1}", httpSessionId, ssoId);
this.idMapper.map(ssoId, principal, httpSessionId);
}
private void cacheEntryModified(CacheEntryModifiedEvent event) {
if (! (event.getKey() instanceof String) || ! (event.getValue() instanceof String[])) {
return;
}
String httpSessionId = (String) event.getKey();
String[] value = (String[]) event.getValue();
String ssoId = value[0];
String principal = value[1];
LOG.tracev("cacheEntryModified {0}:{1}", httpSessionId, ssoId);
this.idMapper.removeSession(httpSessionId);
this.idMapper.map(ssoId, principal, httpSessionId);
}
private void cacheEntryRemoved(CacheEntryRemovedEvent event) {
if (! (event.getKey() instanceof String)) {
return;
}
LOG.tracev("cacheEntryRemoved {0}", event.getKey());
this.idMapper.removeSession((String) event.getKey());
}
}
+13 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML EAP Integration</name>
@@ -30,6 +30,18 @@
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-parent</artifactId>
<version>${jboss.as.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>adapter</module>
<module>subsystem</module>
+1 -2
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -88,7 +88,6 @@
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.1.0.GA</version>
</dependency>
<dependency>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -24,6 +24,7 @@ import java.io.Serializable;
import java.security.Principal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@@ -31,6 +32,9 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class SamlPrincipal implements Serializable, Principal {
public static final String DEFAULT_ROLE_ATTRIBUTE_NAME = "Roles";
private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
private MultivaluedHashMap<String, String> friendlyAttributes = new MultivaluedHashMap<>();
private String name;
@@ -98,6 +102,15 @@ public class SamlPrincipal implements Serializable, Principal {
}
/**
* Convenience function that gets the attributes associated with this principal
*
* @return attributes associated with this principal
*/
public Map<String, List<String>> getAttributes() {
return Collections.unmodifiableMap(attributes);
}
/**
* Convenience function that gets Attribute value by attribute friendly name
*
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>2.5.5.Final</version>
<version>3.1.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -17,6 +17,7 @@
package org.keycloak.adapters.saml;
import org.keycloak.adapters.saml.SamlDeployment.IDP.SingleSignOnService;
import org.jboss.logging.Logger;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.HttpFacade;
@@ -95,21 +96,22 @@ public abstract class AbstractInitiateLogin implements AuthChallenge {
nameIDPolicyFormat = JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get();
}
SingleSignOnService sso = deployment.getIDP().getSingleSignOnService();
SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
.destination(deployment.getIDP().getSingleSignOnService().getRequestBindingUrl())
.destination(sso.getRequestBindingUrl())
.issuer(issuerURL)
.forceAuthn(deployment.isForceAuthentication()).isPassive(deployment.isIsPassive())
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat));
if (deployment.getIDP().getSingleSignOnService().getResponseBinding() != null) {
if (sso.getResponseBinding() != null) {
String protocolBinding = JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get();
if (deployment.getIDP().getSingleSignOnService().getResponseBinding() == SamlDeployment.Binding.POST) {
if (sso.getResponseBinding() == SamlDeployment.Binding.POST) {
protocolBinding = JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get();
}
authnRequestBuilder.protocolBinding(protocolBinding);
}
if (deployment.getAssertionConsumerServiceUrl() != null) {
authnRequestBuilder.assertionConsumerUrl(deployment.getAssertionConsumerServiceUrl());
if (sso.getAssertionConsumerServiceUrl() != null) {
authnRequestBuilder.assertionConsumerUrl(sso.getAssertionConsumerServiceUrl());
}
return authnRequestBuilder;
}
Loaded 100 of 1641 files, more files were not shown because too many files have changed in this diff. Show more