Compare commits

...
Author SHA1 Message Date
keycloak a20f65fc24 Merge pull request #175 from patriot1burke/master
last example dist fix
2014-01-23 07:54:52 -08:00
Bill Burke 7d6c76cb36 last example dist fix 2014-01-23 10:54:24 -05:00
keycloak 0195e53768 Merge pull request #174 from patriot1burke/master
example dist fixes
2014-01-23 07:46:25 -08:00
Bill Burke 8c4acb2ade example dist fixes 2014-01-23 10:46:04 -05:00
keycloak 1e75f700b8 Merge pull request #173 from patriot1burke/master
distro fixes
2014-01-23 06:55:51 -08:00
Bill Burke 5d5776d255 distro fixes 2014-01-23 09:55:03 -05:00
keycloak c925a76998 Merge pull request #172 from patriot1burke/master
dist
2014-01-22 16:18:30 -08:00
Bill Burke c77a6dfc40 dist 2014-01-22 19:18:00 -05:00
keycloak ef6a0ed8e1 Merge pull request #170 from patriot1burke/master
error screen
2014-01-21 10:06:21 -08:00
Bill Burke cbd1e0aad5 error screen 2014-01-21 13:05:56 -05:00
stianst c0ab3c602c Merge pull request #169 from stianst/master
Fixed keycloak logo in forms and added svgs
2014-01-21 09:18:39 -08:00
Stian Thorgersen 7c8eba14a0 Fixed keycloak logo in forms and added svgs 2014-01-21 17:18:10 +00:00
stianst 3c91caf2b5 Merge pull request #168 from stianst/master
Doc for OpenShift cartridge
2014-01-21 06:41:30 -08:00
Stian Thorgersen ebf80b6deb Updated openshift cartridge url 2014-01-21 14:40:05 +00:00
Stian Thorgersen a5fbde222f Added doc for OpenShift cartridge 2014-01-21 14:01:03 +00:00
stianst 66090e5cca Merge pull request #167 from stianst/master
Minor updates
2014-01-20 11:31:36 -08:00
Stian Thorgersen e92980b776 Simplified check for ssl, since x-forward is sorted by Undertow 2014-01-20 19:31:02 +00:00
Stian Thorgersen 851401c40a Update link to WildFly doc for tuning sockets to point to Undertow docs 2014-01-20 19:30:07 +00:00
stianst 6865352d55 Merge pull request #166 from stianst/master
Updated instructions for configuring SSL
2014-01-20 09:47:03 -08:00
Stian Thorgersen 33ff1c618d Updated instructions for configuring SSL 2014-01-20 17:46:33 +00:00
stianst 564ec7ba05 Merge pull request #165 from stianst/master
Social login docs
2014-01-20 06:38:39 -08:00
Stian Thorgersen ee3506ec98 Social login docs 2014-01-20 14:38:11 +00:00
stianst c3811e2bfb Merge pull request #164 from stianst/master
Documentation, and some minor improvements to admin console
2014-01-20 02:44:28 -08:00
Stian Thorgersen fa677055cc Minor improvements to email config in admin console. Added documentation for configuring smtp server 2014-01-20 10:31:47 +00:00
Stian Thorgersen 2b38df9495 Moved social config instructions from admin console to documentation 2014-01-20 09:43:48 +00:00
Bill Burke d34c73f9b9 Merge pull request #163 from patriot1burke/master
minor changes
2014-01-17 09:27:54 -08:00
Bill Burke d8df697ccf minor changes 2014-01-17 12:27:21 -05:00
Bill Burke 06160d6981 Merge pull request #162 from patriot1burke/master
remove wildfly-demo
2014-01-17 07:33:49 -08:00
Bill Burke 93210fd4f8 remove wildfly-demo 2014-01-17 10:33:17 -05:00
Bill Burke 93f9d39ea2 Merge pull request #161 from patriot1burke/master
demo-template
2014-01-17 07:31:39 -08:00
Bill Burke d8ac7ab656 merge 2014-01-17 10:30:50 -05:00
stianst c0a1090733 Merge pull request #160 from stianst/master
Acct mgnmt always enabled. Rename registration to default roles.
2014-01-17 02:07:51 -08:00
Stian Thorgersen 070c0ddba4 Renamed registration to default roles, add default roles to all users when they are created 2014-01-17 10:03:13 +00:00
Stian Thorgersen c5366f1c81 KEYCLOAK-264 Remove option to enable/disable acct mngmt 2014-01-17 09:30:56 +00:00
Bill Burke cf3aa24ba5 demo-template 2014-01-16 22:16:50 -05:00
stianst 7a6f67dfdd Merge pull request #159 from stianst/master
KEYCLOAK-64 KEYCLOAK-246 Updated social to use update profile required a...
2014-01-16 05:38:05 -08:00
Stian Thorgersen dcfb83b0f2 KEYCLOAK-64 KEYCLOAK-246 Updated social to use update profile required action instead of registration form. Fixed Google provider 2014-01-16 12:52:46 +00:00
Bill Burke 9143901ec6 Merge pull request #158 from patriot1burke/master
jiras
2014-01-15 18:11:52 -08:00
Bill Burke 41974795ce KEYCLOAK-262 2014-01-15 21:10:57 -05:00
Bill Burke b162190c7f remove cookieLoginAllowed 2014-01-15 20:31:01 -05:00
Bill Burke 7294235534 Merge pull request #157 from patriot1burke/master
role name instead of id
2014-01-15 16:40:03 -08:00
Bill Burke 894c28c64f role name instead of id 2014-01-15 19:39:21 -05:00
Bill Burke bb38562f4f Merge pull request #156 from patriot1burke/master
use app name instead of id
2014-01-15 13:57:38 -08:00
Bill Burke ed0d33126c use app name instead of id 2014-01-15 16:57:12 -05:00
Bill Burke f52883333a Merge pull request #155 from patriot1burke/master
auth-server-url and realm/app name changes
2014-01-15 07:03:39 -08:00
Bill Burke 6326d5d2b5 auth-server-url and Realm/App name changes 2014-01-15 10:02:56 -05:00
Bill Burke 0fe9318fa4 Merge pull request #154 from patriot1burke/master
realm name instead of id
2014-01-14 13:15:35 -08:00
Bill Burke 6b388918c9 Merge remote-tracking branch 'upstream/master' 2014-01-14 16:15:09 -05:00
Bill Burke cb391eb89a finish using realm name instead of id 2014-01-14 16:13:52 -05:00
Bill Burke 2dbd7cfa02 realm name for url param 2014-01-14 13:03:13 -05:00
Bill Burke 4825974edc realm name in url 2014-01-13 23:38:00 -05:00
Bill Burke 62cc002396 constants 2014-01-13 19:42:34 -05:00
Bill Burke 8037b02ad8 Merge pull request #153 from patriot1burke/master
change uri scheme
2014-01-13 14:08:39 -08:00
Bill Burke 39b61728d6 change uri scheme 2014-01-13 17:07:36 -05:00
Bill Burke 355d4bdf91 Merge remote-tracking branch 'upstream/master' 2014-01-13 13:57:36 -05:00
Bill Burke 99016c185f Merge pull request #134 from mposolda/master
KEYCLOAK-230 KEYCLOAK-231
2014-01-13 10:57:12 -08:00
Bill Burke b59e60ff38 Merge pull request #151 from patriot1burke/master
docs
2014-01-13 10:55:52 -08:00
Bill Burke c751d8b60f Merge remote-tracking branch 'upstream/master' 2014-01-13 13:04:18 -05:00
mposolda ba0d780380 Added third-party-cdi example. Example in both AS7 and Wildfly 2014-01-13 18:49:32 +01:00
mposolda d309fab825 KEYCLOAK-231 Support for sending scope parameter from applications and oauth clients 2014-01-13 18:41:00 +01:00
mposolda e904ca8b58 KEYCLOAK-230 Convert third-party example to be CDI+JSF application with reading config from JSON file. Renamed package org.jboss.resteasy to org.keycloak in database example. Added ServletOAuthClientConfigLoader 2014-01-13 18:41:00 +01:00
Stian Thorgersen 2e40e63c4c Updated keycloak logo + added favicon 2014-01-13 17:26:19 +00:00
Stian Thorgersen d6512f0333 Fix build error 2014-01-13 16:49:17 +00:00
Bill Burke 4b6ebc339f readme conflict 2014-01-13 11:30:16 -05:00
Bill Burke 5df362a523 Merge remote-tracking branch 'upstream/master'
Conflicts:
	examples/wildfly-demo/README.md
2014-01-13 11:30:01 -05:00
stianst b684357022 Merge pull request #152 from stianst/master
Keycloak welcome-page. Added logo to login and registration forms. Some minor updates to WildFly example README.md
2014-01-13 07:18:17 -08:00
Stian Thorgersen 354abf8a4a Added Keycloak logo to login and registration forms 2014-01-13 15:11:06 +00:00
Stian Thorgersen f2c0eed8f2 Minor tweaks to login. Display 'Keycloak Administration' instead of 'Keycloak' when login to admin console. Add link to powered by Keycloak 2014-01-13 15:06:03 +00:00
Stian Thorgersen 8ef194a205 Added Keycloak welcome page 2014-01-13 15:04:53 +00:00
Stian Thorgersen 6146dd48f7 Some minor changes to WildFly example README.md 2014-01-13 13:56:05 +00:00
Stian Thorgersen 739866de0c KEYCLOAK-255 Added tmp redirect to admin/index.html as work-around to WildFly issue 2014-01-13 11:27:02 +00:00
Stian Thorgersen 90f125b03a KEYCLOAK-236 Fix removing registration realm role 2014-01-13 11:10:11 +00:00
Stian Thorgersen 50082de51d KEYCLOAK-257 Fixed styling of import realm 2014-01-13 10:36:16 +00:00
Bill Burke 8b66234ab9 docs 2014-01-12 20:57:31 -05:00
stianst 86b9fb688c Merge pull request #150 from stianst/master
KEYCLOAK-258 Fix roles missing for apps in registration
2014-01-10 09:41:03 -08:00
Stian Thorgersen 4dd9170a99 KEYCLOAK-258 Fix roles missing for apps in registration 2014-01-10 17:40:20 +00:00
stianst 626839f0f3 Merge pull request #149 from stianst/master
Added oauth client installation to admin console. Rename JWT prn to sub.
2014-01-10 09:07:15 -08:00
Stian Thorgersen 6647ddb66e KEYCLOAK-252 Show error page (or 406) if realm requires https and http is used 2014-01-10 17:04:52 +00:00
Stian Thorgersen 0a57ba026b KEYCLOAK-180 Renamed JWT prn to sub 2014-01-10 10:22:58 +00:00
Stian Thorgersen f14931d234 KEYCLOAK-251 Added installation page for oauth clients to admin console 2014-01-10 10:17:39 +00:00
stianst fcac30d3a2 Merge pull request #148 from stianst/master
Update instructions to add Google. Updated Undertow to version in WildFly CR1
2014-01-09 09:12:05 -08:00
Stian Thorgersen aaae0ff2f7 Updated Undertow to same version as in WildFly CR1 2014-01-09 17:06:58 +00:00
Stian Thorgersen f63872b8b0 KEYCLOAK-228 Updated instructions to add Google 2014-01-09 17:06:29 +00:00
Bill Burke ddbb63f3d1 wildfly example readme 2014-01-07 15:01:17 -05:00
Bill Burke 7daa6f492e Merge pull request #147 from patriot1burke/master
distro
2014-01-07 11:39:11 -08:00
Bill Burke 60f30446ba Merge remote-tracking branch 'upstream/master' 2014-01-07 14:38:25 -05:00
Bill Burke 734bc5c902 distro 2014-01-07 14:37:50 -05:00
Bill Burke d8ef13c133 Merge pull request #145 from patriot1burke/master
wildfly deployment structure.xml
2014-01-02 13:35:14 -08:00
Bill Burke a1b7297f25 wildfly deployment structure.xml 2014-01-02 16:24:04 -05:00
Bill Burke e393a347cc Merge pull request #144 from patriot1burke/master
undertow logout
2013-12-19 15:35:53 -08:00
Bill Burke 30cb9df307 undertow logout 2013-12-19 18:32:47 -05:00
Bill Burke 834baf0e27 refactor admin actions 2013-12-19 15:22:15 -05:00
Bill Burke f78a306ba0 Merge pull request #143 from ammendonca/KEYCLOAK-127
KEYCLOAK-127: Add different message when using "View all users", since m...
2013-12-19 06:52:52 -08:00
ammendonca 69b25407b1 KEYCLOAK-127: Add different message when using "View all users", since modifying the query won't help. 2013-12-19 12:45:17 +00:00
Bill Burke e17c7c2c1b Merge pull request #142 from patriot1burke/master
undertow/wildfly adapter
2013-12-18 15:11:32 -08:00
Bill Burke 40e8a26a3b threadlocal 2013-12-18 18:10:28 -05:00
Bill Burke 0ec80f6590 remove ThreadLocal SkeletonKeySession 2013-12-18 18:08:48 -05:00
Bill Burke 16f5bbc54e undertow/wildfly adapter fixes 2013-12-18 18:01:47 -05:00
Stian Thorgersen 212aec8ae3 KEYCLOAK-235 Fix test 2013-12-18 16:58:31 +00:00
Bill Burke dd84679e3f Merge pull request #140 from cardosogabriel/master
Design for KEYCLOAK-238
2013-12-17 15:17:19 -08:00
Bill Burke c755c7562c Merge pull request #141 from patriot1burke/master
installation text
2013-12-17 15:17:00 -08:00
Bill Burke cbf46720c7 installation text 2013-12-17 18:16:17 -05:00
Gabriel Cardoso bbd3ac22d1 Merge remote-tracking branch 'upstream/master' 2013-12-17 17:05:21 -02:00
Gabriel Cardoso d1693c9c7e Design for KEYCLOAK-238 2013-12-17 17:05:07 -02:00
Bill Burke 36bdd43488 Merge pull request #139 from patriot1burke/master
fix dependency
2013-12-17 09:22:36 -08:00
Bill Burke 1f63e87cd6 fix dependency 2013-12-17 12:22:16 -05:00
Bill Burke addefbb587 Merge pull request #138 from patriot1burke/master
refactor out resteasy from adapters
2013-12-17 09:08:00 -08:00
Bill Burke 1f8081629e Merge remote-tracking branch 'upstream/master' 2013-12-17 12:07:20 -05:00
Bill Burke 6380dc3d1b refactor out resteasy from adapters 2013-12-17 12:07:02 -05:00
Bill Burke 6fe9a03997 Merge pull request #137 from patriot1burke/master
factor out jwt/jose/jws
2013-12-16 08:21:16 -08:00
Bill Burke ac64eba667 Merge remote-tracking branch 'upstream/master' 2013-12-16 11:20:04 -05:00
Bill Burke d22b6f8df7 factor out jwt/jose/jws 2013-12-16 11:19:46 -05:00
Bill Burke 4e03ca51af Merge pull request #136 from patriot1burke/master
refactor core/adapter
2013-12-13 16:54:01 -08:00
Bill Burke d28b1ff98b refactor core/adapter 2013-12-13 19:53:02 -05:00
stianst 698b5a1a16 Merge pull request #135 from cardosogabriel/master
KEYCLOAK-234: In the user account area, there is a useless icon (user) at the header
2013-12-13 01:34:57 -08:00
Gabriel Cardoso 07e003325b KEYCLOAK-234 2013-12-12 21:20:57 -02:00
Stian Thorgersen c7b096cf7d KEYCLOAK-229 Add option to disable registration on first social login 2013-12-11 18:27:59 +00:00
Stian Thorgersen a144ab07f2 Merge branch 'master' of https://github.com/cardosogabriel/keycloak into cardosogabriel-master
Conflicts:
	forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
2013-12-11 14:47:18 +00:00
Stian Thorgersen fbe8c5cdec Added SocialLoader to social core 2013-12-11 14:24:18 +00:00
Stian Thorgersen 00a7d88dee Replaced javax.imageio.spi.ServiceRegistry with java.util.ServiceLoader 2013-12-11 14:24:18 +00:00
stianst a4842fe6bc Merge pull request #133 from ammendonca/KEYCLOAK-222
KEYCLOAK-222: Add proper tooltip and cursor for realm refresh icon.
2013-12-11 06:17:00 -08:00
stianst 6d9e1ea60c Merge pull request #132 from ammendonca/KEYCLOAK-134
KEYCLOAK-134: Increase notification time from 3 to 5 seconds.
2013-12-11 06:16:20 -08:00
stianst 11524e28db Merge pull request #131 from mposolda/master
KEYCLOAK-224 KEYCLOAK-226 KEYCLOAK-225
2013-12-11 06:15:57 -08:00
stianst ad249112bf Merge pull request #130 from ammendonca/KEYCLOAK-200
KEYCLOAK-200: Add tabindex to toggle element and use JS to use space/ent...
2013-12-11 06:14:47 -08:00
stianst ab636f4af5 Merge pull request #128 from vrockai/VARIOUS1
Several UI fixes
2013-12-11 05:51:32 -08:00
ammendonca ad3c964be7 KEYCLOAK-222: Add proper tooltip and cursor for realm refresh icon. 2013-12-10 17:09:14 +00:00
ammendonca 42c7687309 KEYCLOAK-134: Increase notification time from 3 to 5 seconds. 2013-12-10 16:21:46 +00:00
mposolda 8e3e99f392 KEYCLOAK-225 NPe after login when 'Verify email' is enabled but SMTP is not configured 2013-12-10 16:30:12 +01:00
mposolda bec267237a KEYCLOAK-226 Display header To in email message sent from Keycloak 2013-12-10 16:05:13 +01:00
mposolda a2e312b3f1 KEYCLOAK-224 Adding KeycloakSessionDestroyListener to web.xml of AS7 and Wildfly demo. Removing MongoRunnerListener from WildFly demo as Mongo is disabled 2013-12-10 11:50:50 +01:00
ammendonca 94a70e78ca KEYCLOAK-200: Add tabindex to toggle element and use JS to use space/enter to toggle it. 2013-12-10 10:40:00 +00:00
Stian Thorgersen 7076341f7f Moved default button on login form to right 2013-12-10 09:42:16 +00:00
Gabriel Cardoso e052b6f99f Design adjustments 2013-12-10 02:10:38 -02:00
vrockai 809c4b3673 KEYCLOAK-206 KEYCLOAK-207 SMTP config page fix 2013-12-09 15:17:28 +01:00
vrockai 331f321274 KEYCLOAK-203 KEYCLOAK-210 fixed role menu conditions 2013-12-09 14:27:32 +01:00
vrockai 07f9fd3de3 KEYCLOAK-212 placeholder page for app sessions 2013-12-09 11:52:41 +01:00
Stian Thorgersen 53e61326c1 Set status code to internal server error on error pages 2013-12-07 16:00:13 +00:00
Stian Thorgersen faec1e5340 Fix error when showing credentials for oauth client 2013-12-07 14:18:26 +00:00
Stian Thorgersen 6e13dc8db7 KEYCLOAK-204 2013-12-07 13:55:35 +00:00
Stian Thorgersen 145eab98d8 KEYCLOAK-221 Don't require username to recover password 2013-12-07 13:34:31 +00:00
Stian Thorgersen cd8c8d52e8 KEYCLOAK-217 Add option to recover username 2013-12-07 13:18:06 +00:00
Stian Thorgersen 0dad786b35 KEYCLOAK-220 Fix login to realm with space in id, KEYCLOAK-199 Add account management to admin realm 2013-12-07 11:35:32 +00:00
Stian Thorgersen 43da684a91 KEYCLOAK-218 Show error page if failed to send email 2013-12-07 11:00:45 +00:00
Stian Thorgersen c368a64b4b KEYCLOAK-215 Remove terms and condition link from registration page 2013-12-07 10:42:30 +00:00
Stian Thorgersen 8011622e25 KEYCLOAK-216 Removed hard-coded 'password updated 2 days ago' in account mngmt / password 2013-12-07 10:28:50 +00:00
Bill Burke 72a330fe85 Merge pull request #127 from patriot1burke/master
realm import/upload
2013-12-06 14:30:47 -08:00
Bill Burke c63abbdf3e Merge remote-tracking branch 'upstream/master' 2013-12-06 17:28:51 -05:00
Bill Burke edba13e596 realm upload 2013-12-06 17:28:32 -05:00
Stian Thorgersen 805863dde6 KEYCLOAK-198 Search or apps 2013-12-06 19:33:37 +00:00
Stian Thorgersen c514e6c152 KEYCLOAK-197 Fix search for users returns users for all realms 2013-12-06 19:22:55 +00:00
Stian Thorgersen a423c38e42 KEYCLOAK-214 view all users in a realm through admin console 2013-12-06 19:09:03 +00:00
Bill Burke 36a20d15e1 Merge pull request #126 from vrockai/VARIOUS1
Many small fixes
2013-12-06 08:14:23 -08:00
vrockai 468a060f55 KEYCLOAK-208 added validation to username and email 2013-12-06 17:01:55 +01:00
vrockai d0f4ac47ea KEYCLOAK-186 added help/info about value types 2013-12-06 17:01:55 +01:00
vrockai e646f0afe5 KEYCLOAK-201 set min and max dimensions for textarea 2013-12-06 17:01:55 +01:00
vrockai e4376604c5 KEYCLOAK-205 fix for the key textarea 2013-12-06 17:01:55 +01:00
vrockai 96c807d761 KEYCLOAK-209 added missing scope value application 2013-12-06 17:01:55 +01:00
vrockai 3ffab32eb3 KEYCLOAK-204 set validation for numbers to time inputs 2013-12-06 17:01:55 +01:00
vrockai 0fdab8c9f1 KEYCLOAK-202 set pointer cursor for action icons 2013-12-06 17:01:55 +01:00
Bill Burke 832c6ebaf1 Merge pull request #125 from patriot1burke/master
version back to SNAPSHOT
2013-12-06 06:46:07 -08:00
Bill Burke b76f625eaf Merge remote-tracking branch 'upstream/master' 2013-12-06 09:45:26 -05:00
Bill Burke d86dec6561 version bump to SNAPSHOT 2013-12-06 09:45:08 -05:00
484 changed files with 15529 additions and 15540 deletions

No files matched your search

Executable
+210
View File
@@ -0,0 +1,210 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<pre>
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
</pre>
</body>
</html>
Regular → Executable
+1 -1
View File
@@ -1,4 +1,4 @@
keycloak
========
SSO SaaS
SSO Service for web apps and REST services.
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-alpha-1-12062013</version>
<version>1.0-alpha-1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,6 +5,12 @@ body {
color: #4d5258;
font-family: "Open Sans", sans-serif;
}
.admin-console #content textarea {
min-width: 10em;
max-width: 74em;
min-height: 10em;
max-height: 50em;
}
/* Feedback */
.feedback-aligner {
top: 0.9em;
@@ -137,90 +143,6 @@ body {
min-height: 42px;
max-width: 1170px;
}
.header.rcue .navbar.primary .nav > li {
/*
.dropdown {
display: inline-block;
margin-left: 0.53846153846154em;
margin-top: 0.46153846153846em;
min-width: 15.3846153846154em;
width: auto;
.dropdown-toggle {
font-size: 0.84615384615385em;
color: #fff;
display: inline-block;
line-height: 2.36363636363636em;
border: 1px solid #676c6e;
border-radius: 2px;
padding: 0 0.54545454545455em;
background: #555a5e url(img/sprite-arrow-down.svg) no-repeat right -26px;
display: block;
&:hover,
&:focus {
text-decoration: none;
}
&:hover {
border-color: #7e8385;
}
}
.dropdown-menu {
left: 0;
min-width: 0;
width: 100%;
overflow: hidden;
li,
li.selected {
width: auto;
a {
width: auto;
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
&:hover {
background-color: #D5ECF9;
background-image: none;
border-bottom: 1px solid #A7D7F1;
border-top: 1px solid #A7D7F1;
color: #4D5258;
}
}
}
li.selected a {
background-color: #2B99C0;
background-image: linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -o-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -moz-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -webkit-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -ms-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, #2EA1CA),
color-stop(1,0, #2792B6)
);
background-repeat: repeat-x;
color: #FFFFFF;
}
}
&.open .dropdown-toggle {
text-decoration: none;
box-shadow: inset 0px 2px 5px rgba(0,0,0,0.2);
border-color: #7e8385;
}
}
*/
}
.header.rcue .navbar.primary .nav > li .dropdown-label {
font-size: 0.84615384615385em;
color: #dbdada;
@@ -396,7 +318,8 @@ body {
display: inline-table;
width: 20em;
}
#content-area #content .input-group input[type="text"] {
#content-area #content .input-group input[type="text"],
#content-area #content .input-group input[type="number"] {
border-radius: 2px 0 0 2px;
}
#content-area #content .input-group button {
@@ -411,6 +334,9 @@ body {
display: inline-block;
margin-top: 1.36363636363636em;
}
#content-area #content .form-group > label + span {
margin-top: 0;
}
.tooltip {
font-family: "Open Sans", sans-serif;
font-size: 1.1em;
@@ -15,6 +15,15 @@ body {
font-family: @open-sans;
}
.admin-console {
#content textarea {
min-width: 10em;
max-width: 74em;
min-height: 10em;
max-height: 50em;
}
}
/* Feedback */
.feedback-aligner {
@@ -243,88 +252,6 @@ body {
.tooltip {
font-size: 0.84615384615385em;
}
/*
.dropdown {
display: inline-block;
margin-left: 0.53846153846154em;
margin-top: 0.46153846153846em;
min-width: 15.3846153846154em;
width: auto;
.dropdown-toggle {
font-size: 0.84615384615385em;
color: #fff;
display: inline-block;
line-height: 2.36363636363636em;
border: 1px solid #676c6e;
border-radius: 2px;
padding: 0 0.54545454545455em;
background: #555a5e url(img/sprite-arrow-down.svg) no-repeat right -26px;
display: block;
&:hover,
&:focus {
text-decoration: none;
}
&:hover {
border-color: #7e8385;
}
}
.dropdown-menu {
left: 0;
min-width: 0;
width: 100%;
overflow: hidden;
li,
li.selected {
width: auto;
a {
width: auto;
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
&:hover {
background-color: #D5ECF9;
background-image: none;
border-bottom: 1px solid #A7D7F1;
border-top: 1px solid #A7D7F1;
color: #4D5258;
}
}
}
li.selected a {
background-color: #2B99C0;
background-image: linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -o-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -moz-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -webkit-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -ms-linear-gradient(top, #2EA1CA 0%, #2792B6 100%);
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0.0, #2EA1CA),
color-stop(1,0, #2792B6)
);
background-repeat: repeat-x;
color: #FFFFFF;
}
}
&.open .dropdown-toggle {
text-decoration: none;
box-shadow: inset 0px 2px 5px rgba(0,0,0,0.2);
border-color: #7e8385;
}
}
*/
}
.button {
@@ -464,7 +391,8 @@ body {
display: inline-table;
width: 20em;
input[type="text"] {
input[type="text"],
input[type="number"] {
border-radius: 2px 0 0 2px;
}
@@ -483,6 +411,10 @@ body {
display: inline-block;
margin-top: 1.36363636363636em;
}
.form-group > label + span {
margin-top: 0;
}
}
}
@@ -820,7 +752,6 @@ table.list {
}
/* Break Points */
@media (max-width: 1200px) {
@@ -19,6 +19,7 @@ textarea {
padding: 0 0.545454545454545em;
height: 2.36363636363636em;
/* 26px */
border: 1px #b6b6b6 solid;
border-radius: 2px;
box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
@@ -315,6 +316,19 @@ button.primary:focus,
width: 20em;
font-weight: normal;
}
.search-comp + span {
font-size: 1.1em;
font-weight: normal;
color: #A1A1A1;
}
.search-comp + span span {
margin-left: 0.45454545454545em;
margin-right: 0.45454545454545em;
display: inline-block;
}
.search-comp + span .link {
font-size: 0.90909090909091em;
}
.feedback-aligner {
position: fixed;
top: 1.5em;
@@ -840,6 +854,10 @@ input[type="email"].tiny {
margin-top: 3em;
margin-bottom: 5em;
}
.form-actions.inside {
margin-top: 0;
margin-bottom: 1em;
}
.form-actions .primary,
.form-actions .destructive {
float: right;
@@ -915,3 +933,51 @@ input[type="email"].tiny {
.breadcrumb > li + li:before {
content: "» ";
}
/* Input file button */
.button-input-file {
float: left;
position: relative;
overflow: hidden;
}
.button-input-file .transparent {
position: absolute;
width: 30em;
height: 30em;
bottom: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
.button-input-file:hover .button {
background-image: none;
}
.uploaded-file {
font-weight: bold;
margin-right: 0.90909090909091em;
padding-top: 0.454545em;
float: left;
}
.link-input-file {
display: inline-block;
position: relative;
overflow: hidden;
margin-top: 0.1em;
}
.link-input-file:hover .link {
text-decoration: underline;
}
.link-input-file .link {
font-size: 1.1em;
}
.link-input-file .transparent {
position: absolute;
width: 30em;
height: 30em;
bottom: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
.link-input-file .link:hover {
cursor: pointer;
}
@@ -323,6 +323,22 @@ button.primary,
font-weight: normal;
}
}
&+ span {
font-size: 1.1em;
font-weight: normal;
color: #A1A1A1;
span {
margin-left: 0.45454545454545em;
margin-right: 0.45454545454545em;
display: inline-block;
}
.link {
font-size: 0.90909090909091em;
}
}
}
.feedback-aligner {
@@ -971,6 +987,11 @@ input[type="email"] {
margin-top: 3em;
margin-bottom: 5em;
&.inside {
margin-top: 0;
margin-bottom: 1em;
}
.primary,
.destructive {
float: right;
@@ -1073,4 +1094,62 @@ input[type="email"] {
> li + li:before {
content: "» ";
}
}
/* Input file button */
.button-input-file {
float: left;
position: relative;
overflow: hidden;
.transparent {
position: absolute;
width: 30em;
height: 30em;
bottom: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
&:hover .button {
background-image: none;
}
}
.uploaded-file {
font-weight: bold;
margin-right: 0.90909090909091em;
padding-top: 0.454545em;
float: left;
}
.link-input-file {
display: inline-block;
position: relative;
overflow: hidden;
margin-top: 0.1em;
&:hover .link {
text-decoration: underline;
}
.link {
font-size: 1.1em;
}
.transparent {
position: absolute;
width: 30em;
height: 30em;
bottom: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
.link:hover {
cursor: pointer;
}
}
@@ -24,9 +24,11 @@ table thead tr th {
padding: 1px;
border-top: none;
}
/*
.rcue-table-actions span:last-child {
float: right;
}
*/
.rcue-table-actions {
padding: 1px;
}
@@ -62,6 +64,10 @@ table tbody tr td:first-child {
table thead tr th:last-child {
border-right: none;
}
table thead tr th button,
table thead tr th .button {
margin-left: 0.72727272727273em;
}
table tbody tr:first-child td {
border-top: 1px solid #f2f2f2;
/* padding-top: 9px; */
@@ -31,9 +31,11 @@ table thead tr th {
border-top: none;
}
/*
.rcue-table-actions span:last-child {
float: right;
}
*/
.rcue-table-actions {
padding: 1px;
@@ -82,6 +84,11 @@ table thead tr th:last-child {
border-right: none;
}
table thead tr th button,
table thead tr th .button {
margin-left: 0.72727272727273em;
}
table tbody tr:first-child td {
border-top: 1px solid #f2f2f2;
/* padding-top: 9px; */
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

After

Width:  |  Height:  |  Size: 1.7 KiB

+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-alpha-1-12062013</version>
<version>1.0-alpha-1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,24 +5,24 @@
<meta charset="utf-8">
<title>Keycloak</title>
<link rel="icon" href="/auth-server/admin-ui/img/favicon.ico">
<link rel="icon" href="/auth/admin-ui/img/favicon.ico">
<!-- Frameworks -->
<link rel="stylesheet" href="/auth-server/admin-ui/css/reset.css">
<link rel="stylesheet" href="/auth-server/admin-ui/bootstrap-3.0.0-wip/css/bootstrap.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/sprites.css">
<link rel="stylesheet" href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic'>
<link rel="stylesheet" href="/auth/admin-ui/css/reset.css">
<link rel="stylesheet" href="/auth/admin-ui/bootstrap-3.0.0-wip/css/bootstrap.css">
<link rel="stylesheet" href="/auth/admin-ui/css/sprites.css">
<link rel="stylesheet" href='//fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic'>
<!-- RCUE styles -->
<link rel="stylesheet" href="/auth-server/admin-ui/css/base.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/forms.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/header.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/tabs.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/icons.css">
<link rel="stylesheet" href="/auth-server/admin-ui/css/tables.css">
<link rel="stylesheet" href="/auth/admin-ui/css/base.css">
<link rel="stylesheet" href="/auth/admin-ui/css/forms.css">
<link rel="stylesheet" href="/auth/admin-ui/css/header.css">
<link rel="stylesheet" href="/auth/admin-ui/css/tabs.css">
<link rel="stylesheet" href="/auth/admin-ui/css/icons.css">
<link rel="stylesheet" href="/auth/admin-ui/css/tables.css">
<!-- Page styles -->
<link rel="stylesheet" href="/auth-server/admin-ui/css/admin-console.css">
<link rel="stylesheet" href="/auth/admin-ui/css/admin-console.css">
<link href="lib/select2-3.4.1/select2.css" rel="stylesheet">
<script src="lib/jquery/jquery-1.10.2.js" type="text/javascript"></script>
@@ -35,10 +35,10 @@
<script src="lib/jquery/jquery.idletimer.js" type="text/javascript"></script>
<script src="lib/jquery/jquery.idletimeout.js" type="text/javascript"></script>
<script src="lib/angular/select2.js" type="text/javascript"></script>
<!--
<script src="/auth-server/admin-ui/bootstrap-3.0.0-wip/js/dropdown.js"></script>
<script src="/auth-server/admin-ui/bootstrap-3.0.0-wip/js/tooltip.js"></script>
<script src="/auth-server/admin-ui/js/bootstrap-tokenfield.js"></script>
<script src="lib/fileupload/angular-file-upload.min.js"></script> <!--
<script src="/auth/admin-ui/bootstrap-3.0.0-wip/js/dropdown.js"></script>
<script src="/auth/admin-ui/bootstrap-3.0.0-wip/js/tooltip.js"></script>
<script src="/auth/admin-ui/js/bootstrap-tokenfield.js"></script>
-->
<script src="js/app.js"></script>
<script src="js/controllers/realm.js"></script>
@@ -82,12 +82,12 @@
$.idleTimeout('#idletimeout', '#idletimeout a', {
idleAfter: 300,
pollingInterval: 60,
keepAliveURL: '/auth-server/rest/saas/keepalive',
keepAliveURL: '/auth/rest/admin/keepalive',
serverResponseEquals: '',
failedRequests: 1,
onTimeout: function(){
$(this).slideUp();
window.location = "/auth-server/rest/saas/logout";
window.location = "/auth/rest/admin/logout";
},
onIdle: function(){
$(this).slideDown(); // show the warning bar
@@ -1,11 +1,11 @@
'use strict';
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2' ]);
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload' ]);
var resourceRequests = 0;
var loadingTimer = -1;
angular.element(document).ready(function ($http) {
$http.get('/auth-server/rest/saas/whoami').success(function(data) {
$http.get('/auth/rest/admin/whoami').success(function(data) {
var auth = {};
auth.user = data;
auth.loggedIn = true;
@@ -16,7 +16,7 @@ angular.element(document).ready(function ($http) {
angular.bootstrap(document, ["keycloak"]);
}).error(function() {
var path = window.location.hash && window.location.hash.substring(1) || '/';
window.location = '/auth-server/rest/saas/login?path=' + path;
window.location = '/auth/rest/admin/login?path=' + path;
});
});
@@ -24,6 +24,7 @@ angular.element(document).ready(function ($http) {
module.config([ '$routeProvider', function($routeProvider) {
$routeProvider
/*
.when('/create/realm', {
templateUrl : 'partials/realm-detail.html',
resolve : {
@@ -33,6 +34,14 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmDetailCtrl'
})
*/
.when('/create/realm', {
templateUrl : 'partials/realm-create.html',
resolve : {
},
controller : 'RealmCreateCtrl'
})
.when('/realms/:realm', {
templateUrl : 'partials/realm-detail.html',
resolve : {
@@ -73,8 +82,8 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmSocialCtrl'
})
.when('/realms/:realm/registration-settings', {
templateUrl : 'partials/realm-registration.html',
.when('/realms/:realm/default-roles', {
templateUrl : 'partials/realm-default-roles.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
@@ -86,7 +95,7 @@ module.config([ '$routeProvider', function($routeProvider) {
return RoleListLoader();
}
},
controller : 'RealmRegistrationCtrl'
controller : 'RealmDefaultRolesCtrl'
})
.when('/realms/:realm/required-credentials', {
templateUrl : 'partials/realm-credentials.html',
@@ -288,12 +297,27 @@ module.config([ '$routeProvider', function($routeProvider) {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function(ApplicationLoader) {
return ApplicationLoader();
},
installation : function(ApplicationInstallationLoader) {
return ApplicationInstallationLoader();
}
},
controller : 'ApplicationInstallationCtrl'
})
.when('/realms/:realm/applications/:application/sessions', {
templateUrl : 'partials/application-sessions.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function(ApplicationLoader) {
return ApplicationLoader();
}
},
controller : 'ApplicationSessionsCtrl'
})
.when('/create/application/:realm', {
templateUrl : 'partials/application-detail.html',
resolve : {
@@ -347,6 +371,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
application : function(OAuthClientLoader) {
return OAuthClientLoader();
},
oauth : function(OAuthClientLoader) {
return OAuthClientLoader();
}
},
controller : 'OAuthClientCredentialsCtrl'
@@ -369,7 +396,21 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'OAuthClientScopeMappingCtrl'
})
.when('/realms/:realm/oauth-clients/:oauth/installation', {
templateUrl : 'partials/oauth-client-installation.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
oauth : function(OAuthClientLoader) {
return OAuthClientLoader();
},
installation : function(OAuthClientInstallationLoader) {
return OAuthClientInstallationLoader();
}
},
controller : 'OAuthClientInstallationCtrl'
})
.when('/create/oauth-client/:realm', {
templateUrl : 'partials/oauth-client-detail.html',
resolve : {
@@ -443,7 +484,7 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location,
if (response.status == 401) {
console.log('session timeout?');
Auth.loggedIn = false;
window.location = '/auth-server/rest/saas/login?path=' + $location.path();
window.location = '/auth/rest/admin/login?path=' + $location.path();
} else if (response.status == 404) {
Notifications.error("Not found");
} else if (response.status) {
@@ -547,7 +588,7 @@ module.directive('onoffswitch', function() {
if (!attrs.offText) { attrs.offText = "OFF"; }
if (!attrs.ngDisabled) { attrs.ngDisabled = false; }
var html = "<span><div class=\"onoffswitch\" data-ng-class=\"{disabled: ngDisabled}\">" +
var html = "<span><div class=\"onoffswitch\" data-ng-class=\"{disabled: ngDisabled}\" tabindex=\"0\" onkeydown=\"var code = event.keyCode || event.which; if (code === 32 || code === 13) { event.stopImmediatePropagation(); event.preventDefault(); $(event.target).find('input').click();}\">" +
"<input type=\"checkbox\" data-ng-model=\"ngModel\" ng-disabled=\"ngDisabled\"" +
" class=\"onoffswitch-checkbox\" name=\"" + attrs.name + "\" id=\"" + attrs.id + "\">" +
"<label for=\"" + attrs.id + "\" class=\"onoffswitch-label\">" +
@@ -621,7 +662,7 @@ module.directive('kcSave', function ($compile, Notifications) {
form.find('.ng-valid').removeClass('error');
$scope['save']();
} else {
Notifications.error("Missing or invalid field")
Notifications.error("Missing or invalid field(s). Please verify the fields in red.")
form.find('.ng-invalid').addClass('error');
form.find('.ng-valid').removeClass('error');
}
@@ -650,6 +691,28 @@ module.directive('kcReset', function ($compile, Notifications) {
}
});
/*
* Used to select the element (invoke $(elem).select()) on specified action list.
* Usages kc-select-action="click mouseover"
* When used in the textarea element, this will select/highlight the textarea content on specified action (i.e. click).
*/
module.directive('kcSelectAction', function ($compile, Notifications) {
return {
restrict: 'A',
compile: function (elem, attrs) {
var events = attrs.kcSelectAction.split(" ");
for(var i=0; i < events.length; i++){
elem.bind(events[i], function(){
elem.select();
});
}
}
}
});
module.filter('remove', function() {
return function(input, remove, attribute) {
if (!input || !remove) {
@@ -54,7 +54,7 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
}
];
ApplicationCredentials.update({ realm : realm.id, application : application.id }, creds,
ApplicationCredentials.update({ realm : realm.realm, application : application.name }, creds,
function() {
Notifications.success('The password has been changed.');
$scope.password = null;
@@ -76,7 +76,7 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
}
];
ApplicationCredentials.update({ realm : realm.id, application : application.id }, creds,
ApplicationCredentials.update({ realm : realm.realm, application : application.name }, creds,
function() {
Notifications.success('The totp was changed.');
$scope.totp = null;
@@ -94,9 +94,10 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
});
});
module.controller('ApplicationSessionsCtrl', function($scope, $location, realm, application) {
$scope.realm = realm;
$scope.application = application;
});
module.controller('ApplicationRoleDetailCtrl', function($scope, realm, application, role, ApplicationRole, $location, Dialog, Notifications) {
$scope.realm = realm;
@@ -121,22 +122,22 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
$scope.save = function() {
if ($scope.create) {
ApplicationRole.save({
realm: realm.id,
application : application.id
realm: realm.realm,
application : application.name
}, $scope.role, function (data, headers) {
$scope.changed = false;
role = angular.copy($scope.role);
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.id + "/applications/" + application.id + "/roles/" + id);
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles/" + id);
Notifications.success("The role has been created.");
});
} else {
ApplicationRole.update({
realm : realm.id,
application : application.id,
roleId : role.id
realm : realm.realm,
application : application.name,
role : role.name
}, $scope.role, function() {
$scope.changed = false;
role = angular.copy($scope.role);
@@ -151,17 +152,17 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/applications/" + application.id + "/roles");
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.role.name, 'role', function() {
$scope.role.$remove({
realm : realm.id,
application : application.id,
roleId : $scope.role.id
realm : realm.realm,
application : application.name,
role : $scope.role.name
}, function() {
$location.url("/realms/" + realm.id + "/applications/" + application.id + "/roles");
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
Notifications.success("The role has been deleted.");
});
});
@@ -179,8 +180,10 @@ module.controller('ApplicationListCtrl', function($scope, realm, applications, A
});
});
module.controller('ApplicationInstallationCtrl', function($scope, realm, installation, ApplicationInstallation, $routeParams) {
module.controller('ApplicationInstallationCtrl', function($scope, realm, installation, application, ApplicationInstallation, $routeParams) {
console.log('ApplicationInstallationCtrl');
$scope.realm = realm;
$scope.application = application;
$scope.installation = installation;
$scope.download = ApplicationInstallation.url({ realm: $routeParams.realm, application: $routeParams.application });
});
@@ -189,7 +192,7 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
console.log('ApplicationDetailCtrl');
$scope.realm = realm;
$scope.create = !application.id;
$scope.create = !application.name;
if (!$scope.create) {
$scope.application= angular.copy(application);
} else {
@@ -230,18 +233,19 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
$scope.save = function() {
if ($scope.create) {
Application.save({
realm: realm.id
realm: realm.realm,
application: ''
}, $scope.application, function (data, headers) {
$scope.changed = false;
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.id + "/applications/" + id);
$location.url("/realms/" + realm.realm + "/applications/" + id);
Notifications.success("The application has been created.");
});
} else {
Application.update({
realm : realm.id,
id : application.id
realm : realm.realm,
id : application.name
}, $scope.application, function() {
$scope.changed = false;
application = angular.copy($scope.application);
@@ -256,16 +260,16 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/applications");
$location.url("/realms/" + realm.realm + "/applications");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.application.name, 'application', function() {
$scope.application.$remove({
realm : realm.id,
id : $scope.application.id
realm : realm.realm,
id : $scope.application.name
}, function() {
$location.url("/realms/" + realm.id + "/applications");
$location.url("/realms/" + realm.realm + "/applications");
Notifications.success("The application has been deleted.");
});
});
@@ -289,7 +293,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.id, application : application.id}, function(){
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name}, function(){
for (var i = 0; i < $scope.realmMappings.length; i++) {
var role = $scope.realmMappings[i];
for (var j = 0; j < $scope.realmRoles.length; j++) {
@@ -306,7 +310,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
});
$scope.addRealmRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/applications/' + application.id + '/scope-mappings/realm',
$http.post('/auth/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@@ -321,7 +325,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteRealmRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/applications/' + application.id + '/scope-mappings/realm',
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@@ -336,7 +340,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/applications/' + application.id + '/scope-mappings/applications/' + $scope.targetApp.id,
$http.post('/auth/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@@ -351,7 +355,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/applications/' + application.id + '/scope-mappings/applications/' + $scope.targetApp.id,
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];
@@ -367,8 +371,8 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
$scope.changeApplication = function() {
$scope.applicationRoles = ApplicationRole.query({realm : realm.id, application : $scope.targetApp.id}, function() {
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.id, application : application.id, targetApp : $scope.targetApp.id}, function(){
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.targetApp.name}, function() {
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name}, function(){
for (var i = 0; i < $scope.applicationMappings.length; i++) {
var role = $scope.applicationMappings[i];
for (var j = 0; j < $scope.applicationRoles.length; j++) {
@@ -42,7 +42,7 @@ module.controller('OAuthClientCredentialsCtrl', function($scope, $location, real
}
];
OAuthClientCredentials.update({ realm : realm.id, oauth : oauth.id }, creds,
OAuthClientCredentials.update({ realm : realm.realm, oauth : oauth.id }, creds,
function() {
Notifications.success('The password has been changed.');
$scope.password = null;
@@ -64,7 +64,7 @@ module.controller('OAuthClientCredentialsCtrl', function($scope, $location, real
}
];
OAuthClientCredentials.update({ realm : realm.id, oauth : oauth.id }, creds,
OAuthClientCredentials.update({ realm : realm.realm, oauth : oauth.id }, creds,
function() {
Notifications.success('The totp was changed.');
$scope.totp = null;
@@ -133,17 +133,17 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
$scope.save = function() {
if ($scope.create) {
OAuthClient.save({
realm: realm.id
realm: realm.realm
}, $scope.oauth, function (data, headers) {
$scope.changed = false;
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.id + "/oauth-clients/" + id);
$location.url("/realms/" + realm.realm + "/oauth-clients/" + id);
Notifications.success("The oauth client has been created.");
});
} else {
OAuthClient.update({
realm : realm.id,
realm : realm.realm,
id : oauth.id
}, $scope.oauth, function() {
$scope.changed = false;
@@ -159,16 +159,16 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/oauth-clients");
$location.url("/realms/" + realm.realm + "/oauth-clients");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.oauth.name, 'oauth', function() {
$scope.oauth.$remove({
realm : realm.id,
realm : realm.realm,
id : $scope.oauth.id
}, function() {
$location.url("/realms/" + realm.id + "/oauth-clients");
$location.url("/realms/" + realm.realm + "/oauth-clients");
Notifications.success("The oauth client has been deleted.");
});
});
@@ -192,7 +192,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
$scope.realmMappings = OAuthClientRealmScopeMapping.query({realm : realm.id, oauth : oauth.id}, function(){
$scope.realmMappings = OAuthClientRealmScopeMapping.query({realm : realm.realm, oauth : oauth.id}, function(){
for (var i = 0; i < $scope.realmMappings.length; i++) {
var role = $scope.realmMappings[i];
for (var j = 0; j < $scope.realmRoles.length; j++) {
@@ -209,7 +209,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
});
$scope.addRealmRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$http.post('/auth/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@@ -224,7 +224,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteRealmRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@@ -239,7 +239,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.id,
$http.post('/auth/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@@ -254,7 +254,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.id,
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];
@@ -270,8 +270,8 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
$scope.changeApplication = function() {
$scope.applicationRoles = ApplicationRole.query({realm : realm.id, application : $scope.targetApp.id}, function() {
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.id, oauth : oauth.id, targetApp : $scope.targetApp.id}, function(){
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.targetApp.name}, function() {
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.id, targetApp : $scope.targetApp.name}, function(){
for (var i = 0; i < $scope.applicationMappings.length; i++) {
var role = $scope.applicationMappings[i];
for (var j = 0; j < $scope.applicationRoles.length; j++) {
@@ -294,3 +294,11 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
});
module.controller('OAuthClientInstallationCtrl', function($scope, realm, installation, oauth, OAuthClientInstallation, $routeParams) {
$scope.realm = realm;
$scope.oauth = oauth;
$scope.installation = installation;
$scope.download = OAuthClientInstallation.url({ realm: $routeParams.realm, oauth: $routeParams.oauth });
});
@@ -4,7 +4,7 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
};
$scope.auth = Auth;
$http.get('/auth-server/rest/saas/whoami').success(function(data, status) {
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
Auth.user = data;
Auth.loggedIn = true;
})
@@ -24,15 +24,14 @@ module.controller('HomeCtrl', function(Realm, $location) {
Realm.query(null, function(realms) {
var realm;
if (realms.length == 1) {
realm = realms[0].id;
realm = realms[0].realm;
} else if (realms.length == 2) {
if (realms[0].realm == 'Keycloak Administration') {
realm = realms[1].id;
} else if (realms[1].realm == 'Keycloak Administration') {
realm = realms[0].id;
if (realms[0].realm == 'keycloak-admin') {
realm = realms[1].realm;
} else if (realms[1].realm == 'administration') {
realm = realms[0].realm;
}
}
if (realm) {
$location.url('/realms/' + realm);
} else {
@@ -50,7 +49,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
// Current.realms = Realm.get();
$scope.current = Current;
$scope.changeRealm = function() {
$location.url("/realms/" + $scope.current.realm.id);
$location.url("/realms/" + $scope.current.realm.realm);
};
$scope.showNav = function() {
var show = Current.realms.length > 0;
@@ -61,31 +60,120 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
}
});
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications) {
console.log('RealmCreateCtrl');
$scope.realm = {
enabled: true
};
$scope.changed = false;
$scope.files = [];
var oldCopy = angular.copy($scope.realm);
$scope.onFileSelect = function($files) {
$scope.files = $files;
};
$scope.changeFileSelect = function() {
$scope.files = null;
document.getElementById('import-file').click();
}
$scope.uploadFile = function() {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $scope.files.length; i++) {
var $file = $scope.files[i];
$scope.upload = $upload.upload({
url: '/auth/rest/admin/realms', //upload.php script, node.js route, or servlet url
// method: POST or PUT,
// headers: {'headerKey': 'headerValue'}, withCredential: true,
data: {myObj: ""},
file: $file
/* set file formData name for 'Content-Desposition' header. Default: 'file' */
//fileFormDataName: myFile,
/* customize how data is added to formData. See #40#issuecomment-28612000 for example */
//formDataAppender: function(formData, key, val){}
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
Notifications.success("The realm has been uploaded.");
$location.url("/realms");
})
.error(function() {
Notifications.error("The realm can not be uploaded. Please verify the file.");
});
//.then(success, error, progress);
}
};
$scope.$watch('realm', function() {
if (!angular.equals($scope.realm, oldCopy)) {
$scope.changed = true;
}
}, true);
$scope.save = function() {
var realmCopy = angular.copy($scope.realm);
var ssl = window.location.protocol == 'https:';
realmCopy.sslNotRequired = !ssl;
console.log('creating new realm **');
Realm.create(realmCopy, function(data, headers) {
var data = Realm.query(function() {
Current.realms = data;
for (var i = 0; i < Current.realms.length; i++) {
if (Current.realms[i].realm == realmCopy.realm) {
Current.realm = Current.realms[i];
}
}
$location.url("/realms/" + realmCopy.realm);
Notifications.success("The realm has been created.");
});
});
};
$scope.cancel = function() {
//$location.url("/realms");
window.history.back();
};
});
module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
$scope.createRealm = !realm.id;
$scope.createRealm = !realm.realm;
console.log('RealmDetailCtrl');
if ($scope.createRealm) {
$scope.realm = {
enabled: true,
requireSsl: true,
cookieLoginAllowed: true
requireSsl: true
};
} else {
if (Current.realm == null || Current.realm.id != realm.id) {
if (Current.realm == null || Current.realm.realm != realm.realm) {
for (var i = 0; i < Current.realms.length; i++) {
if (realm.id == Current.realms[i].id) {
if (realm.realm == Current.realms[i].realm) {
Current.realm = Current.realms[i];
break;
}
}
}
if (Current.realm == null || Current.realm.id != realm.id) {
console.log('realm name: ' + realm.realm);
for (var i = 0; i < Current.realms.length; i++) {
console.log('checking Current.realm:' + Current.realms[i].realm);
if (Current.realms[i].realm == realm.realm) {
Current.realm = Current.realms[i];
}
}
/*
if (Current.realm == null || Current.realm.realm != realm.realm) {
console.log('should be unreachable');
console.log('Why? ' + Current.realms.length + ' ' + Current.realm);
return;
}
*/
$scope.realm = angular.copy(realm);
$scope.realm.requireSsl = !realm.sslNotRequired;
}
@@ -112,16 +200,14 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
if ($scope.createRealm) {
Realm.save(realmCopy, function(data, headers) {
console.log('creating new realm');
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
var data = Realm.query(function() {
Current.realms = data;
for (var i = 0; i < Current.realms.length; i++) {
if (Current.realms[i].id == id) {
if (Current.realms[i].realm == realmCopy.realm) {
Current.realm = Current.realms[i];
}
}
$location.url("/realms/" + id);
$location.url("/realms/" + realmCopy.realm);
Notifications.success("The realm has been created.");
$scope.social = $scope.realm.social;
$scope.registrationAllowed = $scope.realm.registrationAllowed;
@@ -130,18 +216,18 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
} else {
console.log('updating realm...');
$scope.changed = false;
Realm.update(realmCopy, function () {
var id = realmCopy.id;
console.log('oldCopy.realm - ' + oldCopy.realm);
Realm.update({ id : oldCopy.realm}, realmCopy, function () {
var data = Realm.query(function () {
Current.realms = data;
for (var i = 0; i < Current.realms.length; i++) {
if (Current.realms[i].id == id) {
if (Current.realms[i].realm == realmCopy.realm) {
Current.realm = Current.realms[i];
oldCopy = angular.copy($scope.realm);
}
}
});
$location.url("/realms/" + id);
$location.url("/realms/" + realmCopy.realm);
Notifications.success("Your changes have been saved to the realm.");
$scope.social = $scope.realm.social;
$scope.registrationAllowed = $scope.realm.registrationAllowed;
@@ -161,7 +247,7 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
$scope.remove = function() {
Dialog.confirmDelete($scope.realm.realm, 'realm', function() {
Realm.remove({ id : $scope.realm.id }, function() {
Realm.remove({ id : $scope.realm.realm }, function() {
Current.realms = Realm.query();
Notifications.success("The realm has been deleted.");
$location.url("/");
@@ -174,7 +260,7 @@ module.controller('RealmRequiredCredentialsCtrl', function($scope, Realm, realm,
console.log('RealmRequiredCredentialsCtrl');
$scope.realm = {
id : realm.id, realm : realm.realm, social : realm.social,
id : realm.realm, realm : realm.realm, social : realm.social,
requiredCredentials : realm.requiredCredentials,
requiredApplicationCredentials : realm.requiredApplicationCredentials,
requiredOAuthClientCredentials : realm.requiredOAuthClientCredentials,
@@ -192,11 +278,11 @@ module.controller('RealmRequiredCredentialsCtrl', function($scope, Realm, realm,
/* Map used in the table when hovering over (i) icon */
$scope.policyMessages = {
length: "Minimal password length. Default value is 8.",
digits: "Minimal number of digits in password. Default value is 1.",
lowerCase: "Minimal number of lowercase characters in password. Default value is 1.",
upperCase: "Minimal number of uppercase characters in password. Default value is 1.",
specialChars: "Minimal number of special characters in password. Default value is 1."
length: "Minimal password length (integer type). Default value is 8.",
digits: "Minimal number (integer type) of digits in password. Default value is 1.",
lowerCase: "Minimal number (integer type) of lowercase characters in password. Default value is 1.",
upperCase: "Minimal number (integer type) of uppercase characters in password. Default value is 1.",
specialChars: "Minimal number (integer type) of special characters in password. Default value is 1."
}
// $scope.policy is an object representing passwordPolicy string
@@ -325,7 +411,7 @@ module.controller('RealmRequiredCredentialsCtrl', function($scope, Realm, realm,
$scope.changed = false;
Realm.update($scope.realm, function () {
$location.url("/realms/" + realm.id + "/required-credentials");
$location.url("/realms/" + realm.realm + "/required-credentials");
Notifications.success("Your changes have been saved to the realm.");
oldCopy = angular.copy($scope.realm);
});
@@ -343,9 +429,9 @@ module.controller('RealmRequiredCredentialsCtrl', function($scope, Realm, realm,
};
});
module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, applications, roles, Notifications, ApplicationRole, Application) {
module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, applications, roles, Notifications, ApplicationRole, Application) {
console.log('RealmRegistrationCtrl');
console.log('RealmDefaultRolesCtrl');
$scope.realm = realm;
@@ -354,6 +440,12 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
$scope.selectedRealmDefRoles = [];
$scope.applications = angular.copy(applications);
for (var i = 0; i < applications.length; i++) {
if (applications[i].name == 'account') {
$scope.application = $scope.applications[i];
break;
}
}
$scope.availableAppRoles = [];
$scope.selectedAppRoles = [];
@@ -363,7 +455,7 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
$scope.realm.defaultRoles = [];
}
// Populate available roles. Available roles are neither already assigned or system roles.
// Populate available roles. Available roles are neither already assigned
for (var i = 0; i < roles.length; i++) {
var item = roles[i].name;
@@ -417,7 +509,7 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
$scope.selectedAppDefRoles = [];
// Populate available roles for selected application
var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.id, application: $scope.application.id}, function () {
var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.realm, application: $scope.application.name}, function () {
if (!$scope.application.hasOwnProperty('defaultRoles') || $scope.application.defaultRoles === null) {
$scope.application.defaultRoles = [];
@@ -427,8 +519,7 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
for (var i = 0; i < appDefaultRoles.length; i++) {
var roleName = appDefaultRoles[i].name;
if (systemRoles.indexOf(roleName) < 0 && $scope.application.defaultRoles.indexOf(roleName) < 0) {
if ($scope.application.defaultRoles.indexOf(roleName) < 0) {
$scope.availableAppRoles.push(roleName);
}
}
@@ -455,8 +546,8 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
// Update/save the selected application with new default roles.
Application.update({
realm: $scope.realm.id,
id: $scope.application.id
realm: $scope.realm.realm,
id: $scope.application.name
}, $scope.application, function () {
Notifications.success("Your changes have been saved to the application.");
});
@@ -479,8 +570,8 @@ module.controller('RealmRegistrationCtrl', function ($scope, Realm, realm, appli
// Update/save the selected application with new default roles.
Application.update({
realm: $scope.realm.id,
id: $scope.application.id
realm: $scope.realm.realm,
id: $scope.application.name
}, $scope.application, function () {
Notifications.success("Your changes have been saved to the application.");
});
@@ -592,7 +683,7 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
realmCopy.social = true;
$scope.changed = false;
Realm.update(realmCopy, function () {
$location.url("/realms/" + realm.id + "/social-settings");
$location.url("/realms/" + realm.realm + "/social-settings");
Notifications.success("Saved changes to realm");
oldCopy = realmCopy;
});
@@ -605,15 +696,6 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, $location, N
initSocial();
};
$scope.openHelp = function(pId) {
$scope.helpPId = pId;
$scope.providerHelpModal = true;
};
$scope.closeHelp = function() {
$scope.providerHelpModal = false;
};
});
module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications, TimeUnit) {
@@ -661,7 +743,7 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
$scope.changed = false;
Realm.update(realmCopy, function () {
$location.url("/realms/" + realm.id + "/token-settings");
$location.url("/realms/" + realm.realm + "/token-settings");
Notifications.success("Your changes have been saved to the realm.");
});
};
@@ -677,9 +759,9 @@ module.controller('RealmKeysDetailCtrl', function($scope, Realm, realm, $http, $
$scope.generate = function() {
Dialog.confirmGenerateKeys($scope.realm.realm, 'realm', function() {
Realm.update({ id: realm.id, publicKey : 'GENERATE' }, function () {
Realm.update({ id: realm.realm, publicKey : 'GENERATE' }, function () {
Notifications.success('New keys generated for realm.');
Realm.get({ id : realm.id }, function(updated) {
Realm.get({ id : realm.realm }, function(updated) {
$scope.realm = updated;
})
});
@@ -721,20 +803,20 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
$scope.save = function() {
if ($scope.create) {
Role.save({
realm: realm.id
realm: realm.realm
}, $scope.role, function (data, headers) {
$scope.changed = false;
role = angular.copy($scope.role);
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.id + "/roles/" + id);
$location.url("/realms/" + realm.realm + "/roles/" + id);
Notifications.success("The role has been created.");
});
} else {
Role.update({
realm : realm.id,
roleId : role.id
realm : realm.realm,
role : role.name
}, $scope.role, function() {
$scope.changed = false;
role = angular.copy($scope.role);
@@ -749,16 +831,16 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/roles");
$location.url("/realms/" + realm.realm + "/roles");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.role.name, 'role', function() {
$scope.role.$remove({
realm : realm.id,
roleId : $scope.role.id
realm : realm.realm,
role : $scope.role.name
}, function() {
$location.url("/realms/" + realm.id + "/roles");
$location.url("/realms/" + realm.realm + "/roles");
Notifications.success("The role has been deleted.");
});
});
@@ -766,9 +848,13 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
});
module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
console.log('RealmSMTPSettingsCtrl');
var booleanSmtpAtts = ["auth","ssl","starttls"];
$scope.realm = {
id : realm.id, realm : realm.realm, social : realm.social, registrationAllowed : realm.registrationAllowed,
smtpServer: realm.smtpServer
smtpServer: typeObject(realm.smtpServer)
};
var oldCopy = angular.copy($scope.realm);
@@ -782,9 +868,10 @@ module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, real
$scope.save = function() {
var realmCopy = angular.copy($scope.realm);
realmCopy['smtpServer'] = detypeObject(realmCopy.smtpServer);
$scope.changed = false;
Realm.update(realmCopy, function () {
$location.url("/realms/" + realm.id + "/smtp-settings");
$location.url("/realms/" + realm.realm + "/smtp-settings");
Notifications.success("Your changes have been saved to the realm.");
});
};
@@ -793,4 +880,38 @@ module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, real
$scope.realm = angular.copy(oldCopy);
$scope.changed = false;
};
/* Convert string attributes containing a boolean to actual boolean type + convert an integer string (port) to integer. */
function typeObject(obj){
for (var att in obj){
if (booleanSmtpAtts.indexOf(att) < 0)
continue;
if (obj[att] === "true"){
obj[att] = true;
} else if (obj[att] === "false"){
obj[att] = false;
}
}
obj['port'] = parseInt(obj['port']);
return obj;
}
/* Convert all non-string values to strings to invert changes caused by the typeObject function. */
function detypeObject(obj){
for (var att in obj){
if (booleanSmtpAtts.indexOf(att) < 0)
continue;
if (obj[att] === true){
obj[att] = "true";
} else if (obj[att] === false){
obj[att] = "false"
}
}
obj['port'] = obj['port'].toString();
return obj;
}
});
@@ -13,7 +13,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
$scope.realmMappings = RealmRoleMapping.query({realm : realm.id, userId : user.username}, function(){
$scope.realmMappings = RealmRoleMapping.query({realm : realm.realm, userId : user.username}, function(){
for (var i = 0; i < $scope.realmMappings.length; i++) {
var role = $scope.realmMappings[i];
for (var j = 0; j < $scope.realmRoles.length; j++) {
@@ -30,7 +30,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
});
$scope.addRealmRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/users/' + user.username + '/role-mappings/realm',
$http.post('/auth/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@@ -45,7 +45,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.deleteRealmRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/users/' + user.username + '/role-mappings/realm',
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@@ -60,7 +60,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.addApplicationRole = function() {
$http.post('/auth-server/rest/saas/admin/realms/' + realm.id + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.id,
$http.post('/auth/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@@ -75,7 +75,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.deleteApplicationRole = function() {
$http.delete('/auth-server/rest/saas/admin/realms/' + realm.id + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.id,
$http.delete('/auth/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];
@@ -91,8 +91,8 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
$scope.changeApplication = function() {
$scope.applicationRoles = ApplicationRole.query({realm : realm.id, userId : user.username, application : $scope.application.id}, function() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.id, userId : user.username, application : $scope.application.id}, function(){
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, userId : user.username, application : $scope.application.name}, function() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name}, function(){
for (var i = 0; i < $scope.applicationMappings.length; i++) {
var role = $scope.applicationMappings[i];
for (var j = 0; j < $scope.applicationRoles.length; j++) {
@@ -120,15 +120,17 @@ module.controller('UserListCtrl', function($scope, realm, User) {
$scope.realm = realm;
$scope.searchQuery = function() {
$scope.searchLoaded = false;
$scope.currentSearch = $scope.search;
var params = { realm: realm.realm };
if ($scope.search) {
$scope.currentSearch = $scope.search;
$scope.users = User.query({ realm: realm.id, search : $scope.search }, function() {
$scope.searchLoaded = true;
});
} else {
$scope.currentSearch = null;
$scope.users = null;
params.search = $scope.search;
}
$scope.users = User.query(params, function() {
$scope.searchLoaded = true;
$scope.lastSearch = params.search;
});
};
});
@@ -183,17 +185,17 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
$scope.save = function() {
if ($scope.create) {
User.save({
realm: realm.id
realm: realm.realm
}, $scope.user, function () {
$scope.changed = false;
user = angular.copy($scope.user);
$location.url("/realms/" + realm.id + "/users/" + $scope.user.username);
$location.url("/realms/" + realm.realm + "/users/" + $scope.user.username);
Notifications.success("The user has been created.");
});
} else {
User.update({
realm: realm.id,
realm: realm.realm,
userId: $scope.user.username
}, $scope.user, function () {
$scope.changed = false;
@@ -209,16 +211,16 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/users");
$location.url("/realms/" + realm.realm + "/users");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.user.username, 'user', function() {
$scope.user.$remove({
realm : realm.id,
realm : realm.realm,
userId : $scope.user.username
}, function() {
$location.url("/realms/" + realm.id + "/users");
$location.url("/realms/" + realm.realm + "/users");
Notifications.success("The user has been deleted.");
});
});
@@ -257,7 +259,7 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, User, Use
var credentials = [ { type : "password", value : $scope.password } ];
User.update({
realm: realm.id,
realm: realm.realm,
userId: $scope.user.username
}, $scope.user, function () {
@@ -265,7 +267,7 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, User, Use
if ($scope.pwdChange){
UserCredentials.update({
realm: realm.id,
realm: realm.realm,
userId: $scope.user.username
}, credentials, function () {
Notifications.success("The password has been reset. The user is required to change his password on" +
@@ -324,7 +326,7 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, User, Use
module.controller('RoleMappingCtrl', function($scope, realm, User, users, role, RoleMapping, Notifications) {
$scope.realm = realm;
$scope.realmId = realm.realm || realm.id;
$scope.realmId = realm.realm || realm.realm;
$scope.allUsers = User.query({ realm : $scope.realmId });
$scope.users = users;
$scope.role = role;
@@ -64,7 +64,7 @@ module.factory('RoleLoader', function(Loader, Role, $route, $q) {
return Loader.get(Role, function() {
return {
realm : $route.current.params.realm,
roleId : $route.current.params.role
role : $route.current.params.role
}
});
});
@@ -82,7 +82,7 @@ module.factory('ApplicationRoleLoader', function(Loader, ApplicationRole, $route
return {
realm : $route.current.params.realm,
application : $route.current.params.application,
roleId : $route.current.params.role
role : $route.current.params.role
}
});
});
@@ -111,7 +111,7 @@ module.factory('ApplicationLoader', function(Loader, Application, $route, $q) {
return Loader.get(Application, function() {
return {
realm : $route.current.params.realm,
id : $route.current.params.application
application : $route.current.params.application
}
});
});
@@ -152,3 +152,12 @@ module.factory('OAuthClientListLoader', function(Loader, OAuthClient, $route, $q
}
});
});
module.factory('OAuthClientInstallationLoader', function(Loader, OAuthClientInstallation, $route, $q) {
return Loader.get(OAuthClientInstallation, function() {
return {
realm : $route.current.params.realm,
oauth : $route.current.params.oauth
}
});
});
@@ -55,6 +55,9 @@ module.service('Dialog', function($dialog) {
});
module.factory('Notifications', function($rootScope, $timeout) {
// time (in ms) the notifications are shown
var delay = 5000;
var notifications = {};
var scheduled = null;
@@ -66,7 +69,7 @@ module.factory('Notifications', function($rootScope, $timeout) {
scheduled = $timeout(function() {
$rootScope.notification = null;
scheduled = null;
}, 3000);
}, delay);
};
if (!$rootScope.notifications) {
@@ -103,28 +106,33 @@ module.factory('Notifications', function($rootScope, $timeout) {
});
module.factory('Realm', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:id', {
id : '@id'
return $resource('/auth/rest/admin/realms/:id', {
id : '@realm'
}, {
update : {
method : 'PUT'
}
});
},
create : {
method : 'POST',
params : { id : ''}
}
});
});
module.factory('User', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId', {
return $resource('/auth/rest/admin/realms/:realm/users/:userId', {
realm : '@realm',
userId : '@userId'
}, {
update : {
method : 'PUT'
}
update : {
method : 'PUT'
}
});
});
module.factory('UserCredentials', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId/credentials', {
return $resource('/auth/rest/admin/realms/:realm/users/:userId/credentials', {
realm : '@realm',
userId : '@userId'
}, {
@@ -136,14 +144,14 @@ module.factory('UserCredentials', function($resource) {
});
module.factory('RealmRoleMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId/role-mappings/realm', {
return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/realm', {
realm : '@realm',
userId : '@userId'
});
});
module.factory('ApplicationRoleMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
realm : '@realm',
userId : '@userId',
application : "@application"
@@ -151,14 +159,14 @@ module.factory('ApplicationRoleMapping', function($resource) {
});
module.factory('ApplicationRealmScopeMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/scope-mappings/realm', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/realm', {
realm : '@realm',
application : '@application'
});
});
module.factory('ApplicationApplicationScopeMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
realm : '@realm',
application : '@application',
targetApp : '@targetApp'
@@ -168,7 +176,7 @@ module.factory('ApplicationApplicationScopeMapping', function($resource) {
module.factory('RealmRoles', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/roles', {
return $resource('/auth/rest/admin/realms/:realm/roles', {
realm : '@realm'
});
});
@@ -176,9 +184,9 @@ module.factory('RealmRoles', function($resource) {
module.factory('Role', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/roles/:roleId', {
return $resource('/auth/rest/admin/realms/:realm/roles/:role', {
realm : '@realm',
roleId : '@roleId'
role : '@role'
}, {
update : {
method : 'PUT'
@@ -187,10 +195,10 @@ module.factory('Role', function($resource) {
});
module.factory('ApplicationRole', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/roles/:roleId', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/roles/:role', {
realm : '@realm',
application : "@application",
roleId : '@roleId'
role : '@role'
}, {
update : {
method : 'PUT'
@@ -200,9 +208,9 @@ module.factory('ApplicationRole', function($resource) {
module.factory('Application', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:id', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application', {
realm : '@realm',
id : '@id'
application : '@name'
}, {
update : {
method : 'PUT'
@@ -211,8 +219,8 @@ module.factory('Application', function($resource) {
});
module.factory('ApplicationInstallation', function($resource) {
var url = '/auth-server/rest/saas/admin/realms/:realm/applications/:application/installation';
var resource = $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/installation', {
var url = '/auth/rest/admin/realms/:realm/applications/:application/installation';
var resource = $resource('/auth/rest/admin/realms/:realm/applications/:application/installation', {
realm : '@realm',
application : '@application'
}, {
@@ -227,7 +235,7 @@ module.factory('ApplicationInstallation', function($resource) {
});
module.factory('ApplicationCredentials', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/credentials', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/credentials', {
realm : '@realm',
application : '@application'
}, {
@@ -239,7 +247,7 @@ module.factory('ApplicationCredentials', function($resource) {
});
module.factory('ApplicationOrigins', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/allowed-origins', {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/allowed-origins', {
realm : '@realm',
application : '@application'
}, {
@@ -251,7 +259,7 @@ module.factory('ApplicationOrigins', function($resource) {
});
module.factory('OAuthClient', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/oauth-clients/:id', {
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:id', {
realm : '@realm',
id : '@id'
}, {
@@ -262,7 +270,7 @@ module.factory('OAuthClient', function($resource) {
});
module.factory('OAuthClientCredentials', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/oauth-clients/:oauth/credentials', {
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/credentials', {
realm : '@realm',
oauth : '@oauth'
}, {
@@ -274,20 +282,36 @@ module.factory('OAuthClientCredentials', function($resource) {
});
module.factory('OAuthClientRealmScopeMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
realm : '@realm',
oauth : '@oauth'
});
});
module.factory('OAuthClientApplicationScopeMapping', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
realm : '@realm',
oauth : '@oauth',
targetApp : '@targetApp'
});
});
module.factory('OAuthClientInstallation', function($resource) {
var url = '/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation';
var resource = $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation', {
realm : '@realm',
oauth : '@oauth'
}, {
update : {
method : 'PUT'
}
});
resource.url = function(parameters) {
return url.replace(':realm', parameters.realm).replace(':oauth', parameters.oauth);
}
return resource;
});
module.factory('Current', function(Realm, $route) {
var current = {};
@@ -302,7 +326,7 @@ module.factory('Current', function(Realm, $route) {
current.realms = Realm.query(null, function(realms) {
if ($route.current.params.realm) {
for (var i = 0; i < realms.length; i++) {
if (realms[i].id == $route.current.params.realm) {
if (realms[i].realm == $route.current.params.realm) {
current.realm = realms[i];
}
}
@@ -0,0 +1,72 @@
/**!
* FileAPI — a set of tools for working with files
*
* @author RubaXa <trash@rubaxa.org>
* @build lib/canvas-to-blob lib/FileAPI.core lib/FileAPI.Image lib/FileAPI.Form lib/FileAPI.XHR lib/FileAPI.Flash
*/
(function(a){var k=a.HTMLCanvasElement&&a.HTMLCanvasElement.prototype,g;if(g=a.Blob)try{g=Boolean(new Blob)}catch(j){g=!1}var m=g;if(g=m)if(g=a.Uint8Array)try{g=100===(new Blob([new Uint8Array(100)])).size}catch(f){g=!1}var c=g,e=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder,q=(m||e)&&a.atob&&a.ArrayBuffer&&a.Uint8Array&&function(a){var l,f,u,g;l=0<=a.split(",")[0].indexOf("base64")?atob(a.split(",")[1]):decodeURIComponent(a.split(",")[1]);f=new ArrayBuffer(l.length);u=new Uint8Array(f);
for(g=0;g<l.length;g+=1)u[g]=l.charCodeAt(g);a=a.split(",")[0].split(":")[1].split(";")[0];if(m)return new Blob([c?u:f],{type:a});u=new e;u.append(f);return u.getBlob(a)};a.HTMLCanvasElement&&!k.toBlob&&(k.mozGetAsFile?k.toBlob=function(a,c){a(this.mozGetAsFile("blob",c))}:k.toDataURL&&q&&(k.toBlob=function(a,c){a(q(this.toDataURL(c)))}));"function"===typeof define&&define.amd?define(function(){return q}):a.dataURLtoBlob=q})(this);
(function(a,k){function g(b,E,a){if(b)if(l(b))for(var d=0,c=b.length;d<c;d++)d in b&&E.call(a,b[d],d,b);else for(d in b)b.hasOwnProperty(d)&&E.call(a,b[d],d,b)}function j(b,d,a){if(b){var c=h.uid(b);D[c]||(D[c]={});g(d.split(/\s+/),function(d){n?n.event.add(b,d,a):(D[c][d]||(D[c][d]=[]),D[c][d].push(a),b.addEventListener?b.addEventListener(d,a,!1):b.attachEvent?b.attachEvent("on"+d,a):b["on"+d]=a)})}}function m(b,d,a){if(b){var c=h.uid(b),e=D[c]||{};g(d.split(/\s+/),function(d){if(n)n.event.remove(b,
d,a);else{for(var E=e[d]||[],c=E.length;c--;)if(E[c]===a){E.splice(c,1);break}b.addEventListener?b.removeEventListener(d,a,!1):b.detachEvent?b.detachEvent("on"+d,a):b["on"+d]=null}})}}function f(b,d,a){j(b,d,function P(c){m(b,d,P);a(c)})}function c(b,d,a,c,e){b={type:a.type||a,target:b,result:c};h.extend(b,e);d(b)}function e(b,d,a,e){if(h.isFile(b)&&p&&p.prototype["readAs"+a]){var n=new p;j(n,K,function Q(a){var e=a.type;"progress"==e?c(b,d,a,a.target.result,{loaded:a.loaded,total:a.total}):"loadend"==
e?(m(n,K,Q),n=null):c(b,d,a,a.target.result)});try{if(e)n["readAs"+a](e,b);else n["readAs"+a](b)}catch(l){c(b,d,"error",k,{error:l.toString()})}}else c(b,d,"error",k,{error:"filreader_not_support_"+a})}function q(b){var d;b.getAsEntry?d=b.getAsEntry():b.webkitGetAsEntry&&(d=b.webkitGetAsEntry());return d}function t(b,d){if(b)if(b.isFile)b.file(function(b){d(!1,[b])},function(){d("entry_file")});else if(b.isDirectory){var a=[];b.createReader().readEntries(function(b){h.afor(b,function(b,c){t(c,function(c,
e){c||(a=a.concat(e));b?b():d(!1,a)})})},function(){d("directory_reader")})}else t(q(b),d);else d("empty_entry")}function l(b){return"object"==typeof b&&b&&"length"in b}function A(b){b.target||(b.target=a.event&&a.event.srcElement||M);3===b.target.nodeType&&(b.target=event.target.parentNode);return b}var u=1,C=function(){},s=navigator.userAgent,y=a.createObjectURL&&a||a.URL&&URL.revokeObjectURL&&URL||a.webkitURL&&webkitURL,r=a.Blob,v=a.File,p=a.FileReader,w=a.FormData,d=a.XMLHttpRequest,n=a.jQuery,
x=!(!v||!p||!a.Uint8Array&&!w&&!d.prototype.sendAsBinary)&&!(/safari\//i.test(s)&&!/chrome\//i.test(s)&&/windows/i.test(s)),s=x&&"withCredentials"in new d,r=x&&!!r&&!(!r.prototype.webkitSlice&&!r.prototype.mozSlice&&!r.prototype.slice),M=a.document,F=a.dataURLtoBlob,T=/img/i,U=/canvas/i,V=/img|canvas/,L=/input/i,I=/^data:[^,]+,/,G=Math.pow,W=Math.round,z=Number,w=function(b){return W(b*this)},H=new z(1024),N=new z(G(H,2)),J=new z(G(H,3)),G=new z(G(H,4)),D={},O=[],K="abort progress error load loadend",
X="status statusText readyState response responseXML responseText responseBody".split(" "),h={version:"1.2.5",cors:!1,html5:!0,debug:!1,pingUrl:!1,withCredentials:!0,staticPath:"./",flashUrl:0,flashImageUrl:0,accept:{"image/*":"art bm bmp dwg dxf cbr cbz fif fpx gif ico iefs jfif jpe jpeg jpg jps jut mcf nap nif pbm pcx pgm pict pm png pnm qif qtif ras rast rf rp svf tga tif tiff xbm xbm xpm xwd","audio/*":"m4a flac aac rm mpa wav wma ogg mp3 mp2 m3u mod amf dmf dsm far gdm imf it m15 med okt s3m stm sfx ult uni xm sid ac3 dts cue aif aiff wpl ape mac mpc mpp shn wv nsf spc gym adplug adx dsp adp ymf ast afc hps xs",
"video/*":"m4v 3gp nsv ts ty strm rm rmvb m3u ifo mov qt divx xvid bivx vob nrg img iso pva wmv asf asx ogm m2v avi bin dat dvr-ms mpg mpeg mp4 mkv avc vp3 svq3 nuv viv dv fli flv wpl"},chunkSize:0,chunkUploadRetry:0,chunkNetworkDownRetryTimeout:2E3,KB:(H.from=w,H),MB:(N.from=w,N),GB:(J.from=w,J),TB:(G.from=w,G),expando:"fileapi"+(new Date).getTime(),uid:function(b){return b?b[h.expando]=b[h.expando]||h.uid():(++u,h.expando+u)},log:function(){h.debug&&(a.console&&console.log)&&(console.log.apply?
console.log.apply(console,arguments):console.log([].join.call(arguments," ")))},getXHR:function(){var b;if(d)b=new d;else if(a.ActiveXObject)try{b=new ActiveXObject("MSXML2.XMLHttp.3.0")}catch(c){b=new ActiveXObject("Microsoft.XMLHTTP")}return b},isArray:l,support:{dnd:s&&"ondrop"in M.createElement("div"),cors:s,html5:x,chunked:r,dataURI:!0},event:{on:j,off:m,one:f,fix:A},throttle:function(b,d){var c,e;return function(){e=arguments;c||(b.apply(a,e),c=setTimeout(function(){c=0;b.apply(a,e)},d))}},
F:function(){},parseJSON:function(b){return a.JSON&&JSON.parse?JSON.parse(b):(new Function("return ("+b.replace(/([\r\n])/g,"\\$1")+");"))()},trim:function(b){b=String(b);return b.trim?b.trim():b.replace(/^\s+|\s+$/g,"")},defer:function(){var b=[],d,a,c={resolve:function(e,n){c.resolve=C;a=e||!1;for(d=n;n=b.shift();)n(a,d)},then:function(c){a!==k?c(a,d):b.push(c)}};return c},queue:function(b){var d=0,a=0,c=!1,e=!1,n={inc:function(){a++},next:function(){d++;setTimeout(n.check,0)},check:function(){d>=
a&&!c&&n.end()},isFail:function(){return c},fail:function(){!c&&b(c=!0)},end:function(){e||(e=!0,b())}};return n},each:g,afor:function(b,d){var a=0,c=b.length;l(b)&&c--?function B(){d(c!=a&&B,b[a],a++)}():d(!1)},extend:function(b){g(arguments,function(d){g(d,function(d,a){b[a]=d})});return b},isFile:function(b){return x&&b&&b instanceof v},isCanvas:function(b){return b&&U.test(b.nodeName)},getFilesFilter:function(b){return(b="string"==typeof b?b:b.getAttribute&&b.getAttribute("accept")||"")?RegExp("("+
b.replace(/\./g,"\\.").replace(/,/g,"|")+")$","i"):/./},readAsDataURL:function(b,d){h.isCanvas(b)?c(b,d,"load",h.toDataURL(b)):e(b,d,"DataURL")},readAsBinaryString:function(b,d){p&&p.prototype.readAsBinaryString?e(b,d,"BinaryString"):e(b,function(b){if("load"==b.type)try{b.result=h.toBinaryString(b.result)}catch(a){b.type="error",b.message=a.toString()}d(b)},"DataURL")},readAsArrayBuffer:function(b,d){e(b,d,"ArrayBuffer")},readAsText:function(b,d,a){a||(a=d,d="utf-8");e(b,a,"Text",d)},toDataURL:function(b){if("string"==
typeof b)return b;if(b.toDataURL)return b.toDataURL("image/png")},toBinaryString:function(b){return a.atob(h.toDataURL(b).replace(I,""))},readAsImage:function(b,d,a){if(h.isFile(b))if(y){var e=y.createObjectURL(b);e===k?c(b,d,"error"):h.readAsImage(e,d,a)}else h.readAsDataURL(b,function(e){"load"==e.type?h.readAsImage(e.result,d,a):(a||"error"==e.type)&&c(b,d,e,null,{loaded:e.loaded,total:e.total})});else h.isCanvas(b)?c(b,d,"load",b):T.test(b.nodeName)?b.complete?c(b,d,"load",b):f(b,"error abort load",
function B(a){"load"==a.type&&y&&y.revokeObjectURL(b.src);m(b,"error abort load",B);c(b,d,a,b)}):b.iframe?c(b,d,{type:"error"}):(e=new Image,e.src=b.dataURL||b,h.readAsImage(e,d,a))},checkFileObj:function(b){var d={},a=h.accept;"object"==typeof b?d=b:d.name=(b+"").split(/\\|\//g).pop();null==d.type&&(d.type=d.name.split(".").pop());g(a,function(b,a){b=RegExp(b.replace(/\s/g,"|"),"i");b.test(d.type)&&(d.type=a.split("/")[0]+"/"+d.type)});return d},getDropFiles:function(b,d){var a=[],c=(b.originalEvent||
b||"").dataTransfer||{},e=l(c.items)&&c.items[0]&&q(c.items[0]),n=h.queue(function(){d(a)});g((e?c.items:c.files)||[],function(b){n.inc();if(e)t(b,function(b,d){!b&&a.push.apply(a,d);n.next()});else{var d=function(d){d&&a.push(b);n.next()};if(!b.type&&0==b.size%4096&&102400>=b.size)if(p)try{var c=new p;f(c,K,function(b){b="error"!=b.type;d(b);b&&c.abort()});c.readAsDataURL(b)}catch(l){d(!1)}else d(null);else d(!0)}});n.check()},getFiles:function(b,d,a){var c=[];if(a)return h.filterFiles(h.getFiles(b),
d,a),null;b.jquery&&(b.each(function(){c=c.concat(h.getFiles(this))}),b=c,c=[]);"string"==typeof d&&(d=h.getFilesFilter(d));b.originalEvent?b=A(b.originalEvent):b.srcElement&&(b=A(b));b.dataTransfer?b=b.dataTransfer:b.target&&(b=b.target);b.files?c=b.files:!x&&L.test(b&&b.tagName)?h.trim(b.value)&&(c=[h.checkFileObj(b.value)],c[0].blob=b,c[0].iframe=!0):l(b)&&(c=b);return h.filter(c,function(b){return!d||d.test(b.name)})},getInfo:function(b,d){var a={},c=O.concat();h.isFile(b)?function B(){var e=
c.shift();e?e.test(b.type)?e(b,function(b,c){b?d(b):(h.extend(a,c),B())}):B():d(!1,a)}():d("not_support",a)},addInfoReader:function(b,d){d.test=function(d){return b.test(d)};O.push(d)},filter:function(b,d){for(var a=[],c=0,e=b.length,n;c<e;c++)c in b&&(n=b[c],d.call(n,n,c,b)&&a.push(n));return a},filterFiles:function(b,d,a){if(b.length){var c=b.concat(),e,n=[],l=[];(function R(){c.length?(e=c.shift(),h.getInfo(e,function(b,a){(d(e,b?!1:a)?n:l).push(e);R()})):a(n,l)})()}else a([],b)},upload:function(b){b=
h.extend({prepare:h.F,beforeupload:h.F,upload:h.F,fileupload:h.F,fileprogress:h.F,filecomplete:h.F,progress:h.F,complete:h.F,pause:h.F,chunkSize:h.chunkSize,chunkUpoloadRetry:h.chunkUploadRetry},b);b.imageAutoOrientation&&!b.imageTransform&&(b.imageTransform={rotate:"auto"});var d=new h.XHR(b),a=this._getFilesDataArray(b.files),c=0,e=0,n=this,l,f=!1;g(a,function(b){c+=b.size});d.files=[];g(a,function(b){d.files.push(b.file)});d.total=c;d.loaded=0;b.beforeupload(d,b);(l=function S(){var l=a.shift(),
t=l&&l.file,x=!1,u={};g(b,function(b,d){b&&"object"===typeof b&&(b=h.extend({},b));u[d]=b});t&&t.name===h.expando&&(t=null,h.log("[warn] FileAPI.upload() \u2014 called without files"));("abort"!=d.statusText||d.current)&&l?(f=!1,(d.currentFile=t)&&b.prepare(t,u),this._getFormData(u,l,function(a){e||b.upload(d,b);var f=new h.XHR(h.extend({},u,{upload:t?function(){b.fileupload(t,f,u)}:C,progress:t?function(a){x||(b.fileprogress({type:"progress",total:l.total=a.total,loaded:l.loaded=a.loaded},t,f,u),
b.progress({type:"progress",total:c,loaded:d.loaded=e+l.size*(a.loaded/a.total)|0},t,f,u))}:C,complete:function(a){x=!0;g(X,function(b){d[b]=f[b]});t&&(l.loaded=l.total,this.progress(l),e+=l.size,d.loaded=e,b.filecomplete(a,f,t,u));S.call(n)}}));d.abort=function(b){this.current=b;f.abort()};f.send(a)})):(b.complete(200==d.status||201==d.status?!1:d.statusText||"error",d,b),f=!0)}).call(this);d.append=function(b,e){b=h._getFilesDataArray([].concat(b));g(b,function(b){c+=b.size;d.files.push(b.file);
e?a.unshift(b):a.push(b)});f&&l.call(n)};d.remove=function(b){var d=-1;g(a,function(c){d++;if(c.file==b)return a.splice(d,1)})};return d},_getFilesDataArray:function(b){var d=[],a={};if(L.test(b&&b.tagName)){var c=h.getFiles(b);a[b.name||"file"]=null!==b.getAttribute("multiple")?c:c[0]}else l(b)&&L.test(b[0]&&b[0].tagName)?g(b,function(b){a[b.name||"file"]=h.getFiles(b)}):a=b;g(a,function B(b,a){l(b)?g(b,function(b){B(b,a)}):b&&b.name&&d.push({name:a,file:b,size:b.size,total:b.size,loaded:0})});d.length||
d.push({file:{name:h.expando}});return d},_getFormData:function(b,d,a){var c=d.file,e=d.name,n=c.name,l=c.type;d=h.support.transform&&b.imageTransform;var f=new h.Form,t=h.queue(function(){a(f)}),x=d&&(0<parseInt(d.maxWidth||d.minWidth||d.width,10)||d.rotate);h.Image&&d&&(/image/.test(c.type)||V.test(c.nodeType))?(t.inc(),x&&(d=[d]),h.Image.transform(c,d,b.imageAutoOrientation,function(d,a){x&&!d?(!F&&!h.flashEngine&&(a[0]=h.toBinaryString(a[0]),f.multipart=!0),f.append(e,a[0],n,l)):(d||(g(a,function(b,
d){!F&&!h.flashEngine&&(b=h.toBinaryString(b),f.multipart=!0);f.append(e+"["+d+"]",b,n,l)}),e+="[original]"),(d||b.imageOriginal)&&f.append(e,c,n,l));t.next()})):n!==h.expando&&f.append(e,c,n);g(b.data,function Y(b,d){"object"==typeof b?g(b,function(b,a){Y(b,d+"["+a+"]")}):f.append(d,b)});t.check()},reset:function(b){var d,a;n?(a=n(b).clone(!0).insertBefore(b).val("")[0],n(b).remove()):(d=b.parentNode,a=d.insertBefore(b.cloneNode(!0),b),a.value="",d.removeChild(b),g(D[h.uid(b)],function(d,c){g(d,
function(d){m(b,c,d);j(a,c,d)})}));return a},load:function(b,d){var a=h.getXHR();a?(a.open("GET",b,!0),a.overrideMimeType&&a.overrideMimeType("text/plain; charset=x-user-defined"),j(a,"progress",function(b){b.lengthComputable&&d({type:b.type,loaded:b.loaded,total:b.total},a)}),a.onreadystatechange=function(){if(4==a.readyState)if(a.onreadystatechange=null,200==a.status){b=b.split("/");var c={name:b[b.length-1],size:a.getResponseHeader("Content-Length"),type:a.getResponseHeader("Content-Type")};c.dataURL=
"data:"+c.type+";base64,"+h.encode64(a.responseBody||a.responseText);d({type:"load",result:c})}else d({type:"error"})},a.send(null)):d({type:"error"});return a},encode64:function(b){var d="",a=0;for("string"!==typeof b&&(b=String(b));a<b.length;){var c=b.charCodeAt(a++)&255,e=b.charCodeAt(a++)&255,n=b.charCodeAt(a++)&255,l=c>>2,c=(c&3)<<4|e>>4;isNaN(e)?e=n=64:(e=(e&15)<<2|n>>6,n=isNaN(n)?64:n&63);d+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(l)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(c)+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(e)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(n)}return d}};h.addInfoReader(/^image/,function(b,d){if(!b.__dimensions){var a=b.__dimensions=h.defer();h.readAsImage(b,function(b){var d=b.target;a.resolve("load"==b.type?!1:"error",{width:d.width,height:d.height})})}b.__dimensions.then(d)});h.event.dnd=function(b,d,a){var c,e;a||(a=d,d=h.F);p?(j(b,"dragenter dragleave dragover",function(b){for(var a=
((b.originalEvent||b||"").dataTransfer||{}).types,n=a&&a.length;n--;)~a[n].indexOf("File")&&(b.preventDefault(),e!==b.type&&(e=b.type,"dragleave"!=e&&d.call(b.currentTarget,!0,b),clearTimeout(c),c=setTimeout(function(){d.call(b.currentTarget,"dragleave"!=e,b)},50)))}),j(b,"drop",function(b){b.preventDefault();e=0;d.call(b.currentTarget,!1,b);h.getDropFiles(b,function(d){a.call(b.currentTarget,d,b)})})):h.log("Drag'n'Drop -- not supported")};n&&!n.fn.dnd&&(n.fn.dnd=function(b,d){return this.each(function(){h.event.dnd(this,
b,d)})});a.FileAPI=h.extend(h,a.FileAPI);h.flashUrl||(h.flashUrl=h.staticPath+"FileAPI.flash.swf");h.flashImageUrl||(h.flashImageUrl=h.staticPath+"FileAPI.flash.image.swf")})(window);
(function(a,k,g){function j(a,c){if(!(this instanceof j))return new j(a);this.file=a;this.better=!c;this.matrix={sx:0,sy:0,sw:0,sh:0,dx:0,dy:0,dw:0,dh:0,resize:0,deg:0}}var m=Math.min,f=Math.round,c=!1,e={8:270,3:180,6:90};try{c=-1<k.createElement("canvas").toDataURL("image/png").indexOf("data:image/png")}catch(q){}j.prototype={constructor:j,set:function(c){a.extend(this.matrix,c);return this},crop:function(a,c,e,f){e===g&&(e=a,f=c,a=c=0);return this.set({sx:a,sy:c,sw:e,sh:f||e})},resize:function(a,
c,e){"string"==typeof c&&(e=c,c=a);return this.set({dw:a,dh:c,resize:e})},preview:function(a,c){return this.set({dw:a,dh:c||a,resize:"preview"})},rotate:function(a){return this.set({deg:a})},_load:function(c,e){var f=this;a.readAsImage(c,function(a){e.call(f,"load"!=a.type,a.result)})},_apply:function(a,c){var e=k.createElement("canvas"),f=this.getMatrix(a),g=e.getContext("2d"),m=f.deg,q=f.dw,r=f.dh,v=a.width,p=a.height,j,d=a;if(this.better)for(;2<Math.min(v/q,p/r);)v=~~(v/2+0.5),p=~~(p/2+0.5),j=
k.createElement("canvas"),j.width=v,j.height=p,d!==a?(j.getContext("2d").drawImage(d,0,0,d.width,d.height,0,0,v,p),d=j):(d=j,d.getContext("2d").drawImage(a,f.sx,f.sy,f.sw,f.sh,0,0,v,p),f.sx=f.sy=f.sw=f.sh=0);e.width=!(m%180)?q:r;e.height=m%180?q:r;g.rotate(m*Math.PI/180);g.drawImage(d,f.sx,f.sy,f.sw||d.width,f.sh||d.height,180==m||270==m?-q:0,90==m||180==m?-r:0,q,r);c.call(this,!1,e)},getMatrix:function(c){var e=a.extend({},this.matrix),g=e.sw=e.sw||c.width;c=e.sh=e.sh||c.height;var q=e.dw=e.dw||
e.sw,k=e.dh=e.dh||e.sh,s=g/c,j=q/k,r=e.resize;if("preview"==r){if(q!=g||k!=c)if(j>=s?(s=g,r=s/j):(r=c,s=r*j),s!=g||r!=c)e.sx=~~((g-s)/2),e.sy=~~((c-r)/2),g=s,c=r}else r&&("min"==r?(q=f(s<j?m(g,q):k*s),k=f(s<j?q/s:m(c,k))):(q=f(s>=j?m(g,q):k*s),k=f(s>=j?q/s:m(c,k))));e.sw=g;e.sh=c;e.dw=q;e.dh=k;return e},_trans:function(a){this._load(this.file,function(c,e){c?a(c):this._apply(e,a)})},get:function(c){if(a.support.transform){var f=this;"auto"==f.matrix.deg?a.getInfo(this.file,function(a,g){f.matrix.deg=
e[g&&g.exif&&g.exif.Orientation]||0;f._trans(c)}):f._trans(c)}else c("not_support")},toData:function(a){this.get(a)}};j.exifOrientation=e;j.transform=function(c,e,f,q){a.getInfo(c,function(m,k){var y={},r=a.queue(function(a){q(a,y)});m?r.fail():a.each(e,function(a,e){if(!r.isFail()){var l=j(k.nodeType?k:c);if("function"==typeof a)a(k,l);else if(a.width)l[a.preview?"preview":"resize"](a.width,a.height,a.type);else a.maxWidth&&(k.width>a.maxWidth||k.height>a.maxHeight)&&l.resize(a.maxWidth,a.maxHeight,
"max");a.rotate===g&&f&&(a.rotate="auto");l.rotate(a.rotate);r.inc();l.toData(function(d,a){d?r.fail():(y[e]=a,r.next())})}})})};a.support.canvas=a.support.transform=c;a.Image=j})(FileAPI,document);
(function(a,k,g){var j=k.encodeURIComponent,m=k.FormData;k=function(){this.items=[]};k.prototype={append:function(a,c,e,g){this.items.push({name:a,blob:c&&c.blob||(void 0==c?"":c),file:c&&(e||c.name),type:c&&(g||c.type)})},each:function(a){for(var c=0,e=this.items.length;c<e;c++)a.call(this,this.items[c])},toData:function(f,c){c._chunked=a.support.chunked&&0<c.chunkSize&&1==a.filter(this.items,function(a){return a.file}).length;a.support.html5?this.multipart||!m?(a.log("FileAPI.Form.toMultipartData"),
this.toMultipartData(f)):c._chunked?(a.log("FileAPI.Form.toPlainData"),this.toPlainData(f)):(a.log("FileAPI.Form.toFormData"),this.toFormData(f)):(a.log("FileAPI.Form.toHtmlData"),this.toHtmlData(f))},_to:function(f,c,e,g){var m=a.queue(function(){c(f)});this.each(function(a){e(a,f,m,g)});m.check()},toHtmlData:function(f){this._to(g.createDocumentFragment(),f,function(c,e){var f=c.blob,m;c.file?(a.reset(f),f.name=c.name,e.appendChild(f)):(m=g.createElement("input"),m.name=c.name,m.type="hidden",m.value=
f,e.appendChild(m))})},toPlainData:function(a){this._to({},a,function(a,e,f){a.file&&(e.type=a.file);a.blob.toBlob?(f.inc(),a.blob.toBlob(function(g){e.name=a.name;e.file=g;e.size=g.length;e.type=a.type;f.next()},"image/png")):a.file?(e.name=a.blob.name,e.file=a.blob,e.size=a.blob.size,e.type=a.type):(e.params||(e.params=[]),e.params.push(encodeURIComponent(a.name)+"="+encodeURIComponent(a.blob)));e.start=-1;e.end=e.file.FileAPIReadPosition||-1;e.retry=0})},toFormData:function(a){this._to(new m,a,
function(a,e,f){a.file&&e.append("_"+a.name,a.file);a.blob&&a.blob.toBlob?(f.inc(),a.blob.toBlob(function(g){e.append(a.name,g,a.file);f.next()},"image/png")):a.file?e.append(a.name,a.blob,a.file):e.append(a.name,a.blob)})},toMultipartData:function(f){this._to([],f,function(c,e,f,g){var l=!!c.file,m=c.blob,k=function(a){e.push("--_"+g+('\r\nContent-Disposition: form-data; name="'+c.name+'"'+(l?'; filename="'+j(c.file)+'"':"")+(l?"\r\nContent-Type: "+(c.type||"application/octet-stream"):"")+"\r\n\r\n"+
(l?a:j(a))+"\r\n"));f.next()};f.inc();a.isFile(m)?a.readAsBinaryString(m,function(a){"load"==a.type&&k(a.result)}):k(m)},a.expando)}};a.Form=k})(FileAPI,window,document);
(function(a,k){var g=function(){},j=function(a){this.uid=k.uid();this.xhr={abort:g,getResponseHeader:g,getAllResponseHeaders:g};this.options=a};j.prototype={status:0,statusText:"",getResponseHeader:function(a){return this.xhr.getResponseHeader(a)},getAllResponseHeaders:function(){return this.xhr.getAllResponseHeaders()||{}},end:function(m,f){var c=this,e=c.options;c.end=c.abort=g;c.status=m;f&&(c.statusText=f);k.log("xhr.end:",m,f);e.complete(200==m||201==m?!1:c.statusText||"unknown",c);c.xhr&&c.xhr.node&&
setTimeout(function(){var e=c.xhr.node;try{e.parentNode.removeChild(e)}catch(f){}try{delete a[c.uid]}catch(g){}a[c.uid]=c.xhr.node=null},9)},abort:function(){this.end(0,"abort");this.xhr&&(this.xhr.aborted=!0,this.xhr.abort())},send:function(a){var f=this,c=this.options;a.toData(function(a){c.upload(c,f);f._send.call(f,c,a)},c)},_send:function(g,f){var c=this,e,q=c.uid,j=g.url;k.log("XHR._send:",f);j+=(~j.indexOf("?")?"&":"?")+k.uid();f.nodeName?(g.upload(g,c),e=document.createElement("div"),e.innerHTML=
'<form target="'+q+'" action="'+j+'" method="POST" enctype="multipart/form-data" style="position: absolute; top: -1000px; overflow: hidden; width: 1px; height: 1px;"><iframe name="'+q+'" src="javascript:false;"></iframe><input value="'+q+'" name="callback" type="hidden"/></form>',c.xhr.abort=function(){var a=e.getElementsByName("iframe")[0];if(a)try{a.stop?a.stop():a.contentWindow.stop?a.contentWindow.stop():a.contentWindow.document.execCommand("Stop")}catch(c){}e=null},j=e.getElementsByTagName("form")[0],
j.appendChild(f),k.log(j.parentNode.innerHTML),document.body.appendChild(e),c.xhr.node=e,a[q]=function(a,f,g){c.readyState=4;c.responseText=g;c.end(a,f);e=null},c.readyState=2,j.submit(),j=null):this.xhr&&this.xhr.aborted?k.log("Error: already aborted"):(e=c.xhr=k.getXHR(),f.params&&(j+=(0>j.indexOf("?")?"?":"&")+f.params.join("&")),e.open("POST",j,!0),k.withCredentials&&(e.withCredentials="true"),(!g.headers||!g.headers["X-Requested-With"])&&e.setRequestHeader("X-Requested-With","XMLHttpRequest"),
k.each(g.headers,function(a,c){e.setRequestHeader(c,a)}),g._chunked?(e.upload&&e.upload.addEventListener("progress",function(a){f.retry||g.progress({type:a.type,total:f.size,loaded:f.start+a.loaded,totalSize:f.size},c,g)},!1),e.onreadystatechange=function(){c.status=e.status;c.statusText=e.statusText;c.readyState=e.readyState;if(4==e.readyState){for(var a in{"":1,XML:1,Text:1,Body:1})c["response"+a]=e["response"+a];e.onreadystatechange=null;if(!e.status||0<e.status-201)if(k.log("Error: "+e.status),
(!e.status&&!e.aborted||500==e.status||416==e.status)&&++f.retry<=g.chunkUploadRetry){a=e.status?0:k.chunkNetworkDownRetryTimeout;g.pause(f.file,g);var j=parseInt(e.getResponseHeader("X-Last-Known-Byte"),10);k.log("X-Last-Known-Byte: "+j);f.end=j?j:f.start-1;setTimeout(function(){c._send(g,f)},a)}else c.end(e.status);else f.retry=0,f.end==f.size-1?c.end(e.status):(j=parseInt(e.getResponseHeader("X-Last-Known-Byte"),10),k.log("X-Last-Known-Byte: "+j),j&&(f.end=j),f.file.FileAPIReadPosition=f.end,setTimeout(function(){c._send(g,
f)},0));e=null}},f.start=f.end+1,f.end=Math.max(Math.min(f.start+g.chunkSize,f.size)-1,f.start),(q="slice")in f.file||(q="mozSlice")in f.file||(q="webkitSlice"),e.setRequestHeader("Content-Range","bytes "+f.start+"-"+f.end+"/"+f.size),e.setRequestHeader("Content-Disposition","attachment; filename="+encodeURIComponent(f.name)),e.setRequestHeader("Content-Type",f.type||"application/octet-stream"),q=f.file[q](f.start,f.end+1),e.send(q),q=null):(e.upload&&e.upload.addEventListener("progress",k.throttle(function(a){g.progress(a,
c,g)},100),!1),e.onreadystatechange=function(){c.status=e.status;c.statusText=e.statusText;c.readyState=e.readyState;if(4==e.readyState){for(var a in{"":1,XML:1,Text:1,Body:1})c["response"+a]=e["response"+a];e.onreadystatechange=null;c.end(e.status);e=null}},k.isArray(f)?(e.setRequestHeader("Content-Type","multipart/form-data; boundary=_"+k.expando),f=f.join("")+"--_"+k.expando+"--",e.sendAsBinary?e.sendAsBinary(f):(q=Array.prototype.map.call(f,function(a){return a.charCodeAt(0)&255}),e.send((new Uint8Array(q)).buffer))):
e.send(f)))}};k.XHR=j})(window,FileAPI);
(function(a,k,g){var j=a.support,m=k.navigator,f=m.mimeTypes,c=!1;if(m.plugins&&"object"==typeof m.plugins["Shockwave Flash"])c=m.plugins["Shockwave Flash"].description&&!(f&&f["application/x-shockwave-flash"]&&!f["application/x-shockwave-flash"].enabledPlugin);else try{c=!(!k.ActiveXObject||!new ActiveXObject("ShockwaveFlash.ShockwaveFlash"))}catch(e){a.log("ShockwaveFlash.ShockwaveFlash -- does not supported.")}j.flash=c;if(a.support.flash&&(!a.html5||!a.support.html5||a.cors&&!a.support.cors)){var q=
function(a){return('<object id="#id#" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+(a.width||"100%")+'" height="'+(a.height||"100%")+'"><param name="movie" value="#src#" /><param name="flashvars" value="#flashvars#" /><param name="swliveconnect" value="true" /><param name="allowscriptaccess" value="always" /><param name="allownetworking" value="all" /><param name="menu" value="false" /><param name="wmode" value="#wmode#" /><embed flashvars="#flashvars#" swliveconnect="true" allownetworking="all" allowscriptaccess="always" name="#id#" src="#src#" width="'+
(a.width||"100%")+'" height="'+(a.height||"100%")+'" menu="false" wmode="transparent" type="application/x-shockwave-flash"></embed></object>').replace(/#(\w+)#/ig,function(c,e){return a[e]})},t=function(a,c){if(a&&a.style){var e,f;for(e in c){f=c[e];"number"==typeof f&&(f+="px");try{a.style[e]=f}catch(g){}}}},l=function(d,c){a.each(c,function(a,c){var e=d[c];d[c]=function(){this.parent=e;return a.apply(this,arguments)}})},A=function(d){var c=d.wid=a.uid();p._fn[c]=d;return"FileAPI.Flash._fn."+c},
u=function(a){try{p._fn[a.wid]=null,delete p._fn[a.wid]}catch(c){}},C=function(a,c){if(!v.test(a)){if(/^\.\//.test(a)||"/"!=a.charAt(0)){var e=location.pathname,e=e.substr(0,e.lastIndexOf("/"));a=(e+"/"+a).replace("/./","/")}"//"!=a.substr(0,2)&&(a="//"+location.host+a);v.test(a)||(a=location.protocol+a)}c&&(a+=(/\?/.test(a)?"&":"?")+c);return a},s=a.uid(),y=0,r={},v=/^https?:/i,p={_fn:{},init:function(){var d=g.body&&g.body.firstChild;if(d){do if(1==d.nodeType){a.log("FlashAPI.Flash.init...");var c=
g.createElement("div");t(c,{top:1,right:1,width:5,height:5,position:"absolute"});d.parentNode.insertBefore(c,d);p.publish(c,s);return}while(d=d.nextSibling)}10>y&&setTimeout(p.init,50*++y)},publish:function(d,c){d.innerHTML=q({id:c,src:C(a.flashUrl,"r="+a.version),wmode:"transparent",flashvars:"callback=FileAPI.Flash.event&flashId="+c+"&storeKey="+navigator.userAgent.match(/\d/ig).join("")+"_"+a.version+(p.isReady||(a.pingUrl?"&ping="+a.pingUrl:""))})},ready:function(){p.ready=a.F;p.isReady=!0;p.patch();
a.event.on(g,"mouseover",p.mouseover);a.event.on(g,"click",function(a){p.mouseover(a)&&(a.preventDefault?a.preventDefault():a.returnValue=!0)})},getWrapper:function(a){do if(/js-fileapi-wrapper/.test(a.className))return a;while((a=a.parentNode)&&a!==g.body)},mouseover:function(d){d=a.event.fix(d).target;if(/input/i.test(d.nodeName)&&"file"==d.type){var c=d.getAttribute(s);if("i"==c||"r"==c)return!1;if("p"!=c){d.setAttribute(s,"i");var c=g.createElement("div"),e=p.getWrapper(d);if(!e){a.log("flash.mouseover.error: js-fileapi-wrapper not found");
return}t(c,{top:0,left:0,width:d.offsetWidth+100,height:d.offsetHeight+100,zIndex:"1000000",position:"absolute"});e.appendChild(c);p.publish(c,a.uid());d.setAttribute(s,"p")}return!0}},event:function(d){var c=d.type;if("ready"==c){try{p.getInput(d.flashId).setAttribute(s,"r")}catch(e){}p.ready();setTimeout(function(){p.mouseenter(d)},50);return!0}"ping"===c?a.log("(flash -> js).ping:",[d.status,d.savedStatus],d.error):"log"===c?a.log("(flash -> js).log:",d.target):c in p&&setTimeout(function(){a.log("Flash.event."+
d.type+":",d);p[c](d)},1)},mouseenter:function(d){var c=p.getInput(d.flashId);if(c){p.cmd(d,"multiple",null!=c.getAttribute("multiple"));var e=[],f={};a.each((c.getAttribute("accept")||"").split(/,\s*/),function(d){a.accept[d]&&a.each(a.accept[d].split(" "),function(a){f[a]=1})});a.each(f,function(a,d){e.push(d)});p.cmd(d,"accept",e.length?e.join(",")+","+e.join(",").toUpperCase():"*")}},get:function(a){return g[a]||k[a]||g.embeds[a]},getInput:function(d){try{var c=p.getWrapper(p.get(d));if(c)return c.getElementsByTagName("input")[0]}catch(e){a.log('Can not find "input" by flashId:',
d,e)}},select:function(d){var c=p.getInput(d.flashId),e=a.uid(c);d=d.target.files;a.each(d,function(d){a.checkFileObj(d)});r[e]=d;g.createEvent?(e=g.createEvent("Event"),e.initEvent("change",!0,!1),c.dispatchEvent(e)):g.createEventObject&&(e=g.createEventObject(),c.fireEvent("onchange",e))},cmd:function(d,c,e,f){try{return a.log("(js -> flash)."+c+":",e),p.get(d.flashId||d).cmd(c,e)}catch(g){a.log("(js -> flash).onError:",g),f||setTimeout(function(){p.cmd(d,c,e,!0)},50)}},patch:function(){a.flashEngine=
a.support.transform=!0;l(a,{getFiles:function(d,c,e){if(e)return a.filterFiles(a.getFiles(d),c,e),null;var f=a.isArray(d)?d:r[a.uid(d.target||d.srcElement||d)];if(!f)return this.parent.apply(this,arguments);c&&(c=a.getFilesFilter(c),f=a.filter(f,function(a){return c.test(a.name)}));return f},getInfo:function(d,c){if(d&&!d.flashId)this.parent.apply(this,arguments);else{if(!d.__info){var e=d.__info=a.defer();p.cmd(d,"getFileInfo",{id:d.id,callback:A(function F(a,c){u(F);e.resolve(a,d.info=c)})})}d.__info.then(c)}}});
a.support.transform=!0;a.Image&&l(a.Image.prototype,{get:function(a,c){this.set({scaleMode:c||"noScale"});this.parent(a)},_load:function(d,c){a.log("FileAPI.Image._load:",d);if(d&&!d.flashId)this.parent.apply(this,arguments);else{var e=this;a.getInfo(d,function(a){c.call(e,a,d)})}},_apply:function(d,c){a.log("FileAPI.Image._apply:",d);if(d&&!d.flashId)this.parent.apply(this,arguments);else{var e=this.getMatrix(d.info);p.cmd(d,"imageTransform",{id:d.id,matrix:e,callback:A(function F(f,k){a.log("FileAPI.Image._apply.callback:",
f);u(F);if(f)c(f);else if(!a.support.dataURI||3E4<k.length){var j={width:!(e.deg%180)?e.dw:e.dh,height:e.deg%180?e.dw:e.dh,scale:e.scaleMode},l=c,m=function(){try{p.get(s).setImage(k)}catch(d){a.log('flash.setImage -- can not set "base64":',d)}},r,s=a.uid(),z=g.createElement("div");for(r in j)z.setAttribute("data-img-"+r,j[r]);t(z,j);z.innerHTML=q(a.extend({id:s,src:C(a.flashImageUrl,"r="+a.uid()),wmode:"opaque",flashvars:"scale="+j.scale+"&callback="+A(function J(){u(J);setTimeout(m,99);return!0})},
j));l(!1,z);z=null}else{var v=new Image;a.event.one(v,"error abort load",function(a){c("load"!=a.type&&a.type,v);v=null});v.src="data:"+d.type+";base64,"+k}})})}},toData:function(d){var c=this.file,e=c.info,f=this.getMatrix(e);c&&!c.flashId?this.parent.apply(this,arguments):("auto"==f.deg&&(f.deg=a.Image.exifOrientation[e&&e.exif&&e.exif.Orientation]||0),d.call(this,!c.info,{id:c.id,flashId:c.flashId,name:c.name,type:c.type,matrix:f}))}});l(a.Form.prototype,{toData:function(d){for(var c=this.items,
e=c.length;e--;)if(c[e].file&&c[e].blob&&!c[e].blob.flashId)return this.parent.apply(this,arguments);a.log("flash.Form.toData");d(c)}});l(a.XHR.prototype,{_send:function(c,e){if(e.nodeName||e.append&&a.support.html5||a.isArray(e)&&"string"===typeof e[0])return this.parent.apply(this,arguments);var f={},g={},j=this,k,l;a.each(e,function(a){a.file?(g[a.name]=a={id:a.blob.id,name:a.blob.name,matrix:a.blob.matrix,flashId:a.blob.flashId},l=a.id,k=a.flashId):f[a.name]=a.blob});if(!l&&!k)return this.parent.apply(this,
arguments);a.log("flash.XHR._send:",k,l,g);j.xhr={headers:{},abort:function(){p.cmd(k,"abort",{id:l})},getResponseHeader:function(a){return this.headers[a]},getAllResponseHeaders:function(){return this.headers}};var m=a.queue(function(){p.cmd(k,"upload",{url:C(c.url),data:f,files:g,headers:c.headers,callback:A(function I(e){var f=e.type,g=e.result;a.log("flash.upload."+f+":",e);if("progress"==f)e.loaded=Math.min(e.loaded,e.total),e.lengthComputable=!0,c.progress(e);else if("complete"==f)u(I),"string"==
typeof g&&(j.responseText=g.replace(/%22/g,'"').replace(/%5c/g,"\\").replace(/%26/g,"&").replace(/%25/g,"%")),j.end(e.status||200);else if("abort"==f||"error"==f)j.end(e.status||0,e.message),u(I)})})});a.each(g,function(c){m.inc();a.getInfo(c,m.next)});m.check()}})}};a.Flash=p;var w=new Image;a.event.one(w,"error load",function(){a.support.dataURI=!(1!=w.width||1!=w.height);w=null;p.init()});w.src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="}})(FileAPI,window,document);
"undefined"!==typeof ajs&&ajs.loaded&&ajs.loaded("{fileapi}FileAPI.min");"function"===typeof define&&define.amd&&define("FileAPI",[],function(){return window.FileAPI||{}});
@@ -0,0 +1,25 @@
/**!
* AngularJS file upload shim for angular XHR HTML5 browsers
* @author Danial <danial.farid@gmail.com>
* @version 1.1.10
*/
if (window.XMLHttpRequest) {
if (window.FormData) {
// allow access to Angular XHR private field: https://github.com/angular/angular.js/issues/1934
XMLHttpRequest = (function(origXHR) {
return function() {
var xhr = new origXHR();
xhr.send = (function(orig) {
return function() {
if (arguments[0] instanceof FormData && arguments[0].__setXHR_) {
var formData = arguments[0];
formData.__setXHR_(xhr);
}
orig.apply(xhr, arguments);
}
})(xhr.send);
return xhr;
}
})(XMLHttpRequest);
}
}
@@ -0,0 +1,2 @@
/*! 1.1.10 */
window.XMLHttpRequest&&window.FormData&&(XMLHttpRequest=function(a){return function(){var b=new a;return b.send=function(a){return function(){if(arguments[0]instanceof FormData&&arguments[0].__setXHR_){var c=arguments[0];c.__setXHR_(b)}a.apply(b,arguments)}}(b.send),b}}(XMLHttpRequest));
@@ -0,0 +1,215 @@
/**!
* AngularJS file upload shim for HTML5 FormData
* @author Danial <danial.farid@gmail.com>
* @version 1.1.10
*/
(function() {
if (window.XMLHttpRequest) {
if (window.FormData) {
// allow access to Angular XHR private field: https://github.com/angular/angular.js/issues/1934
XMLHttpRequest = (function(origXHR) {
return function() {
var xhr = new origXHR();
xhr.send = (function(orig) {
return function() {
if (arguments[0] instanceof FormData && arguments[0].__setXHR_) {
var formData = arguments[0];
formData.__setXHR_(xhr);
}
orig.apply(xhr, arguments);
}
})(xhr.send);
return xhr;
}
})(XMLHttpRequest);
} else {
XMLHttpRequest = (function(origXHR) {
return function() {
var xhr = new origXHR();
var origSend = xhr.send;
xhr.__requestHeaders = [];
xhr.open = (function(orig) {
xhr.upload = {
addEventListener: function(t, fn, b) {
if (t == 'progress') {
xhr.__progress = fn;
}
}
};
return function(m, url, b) {
orig.apply(xhr, [m, url, b]);
xhr.__url = url;
}
})(xhr.open);
xhr.getResponseHeader = (function(orig) {
return function(h) {
return xhr.__fileApiXHR ? xhr.__fileApiXHR.getResponseHeader(h) : orig.apply(xhr, [h]);
}
})(xhr.getResponseHeader);
xhr.getAllResponseHeaders = (function(orig) {
return function() {
return xhr.__fileApiXHR ? xhr.__fileApiXHR.getAllResponseHeaders() : orig.apply(xhr);
}
})(xhr.getAllResponseHeaders);
xhr.abort = (function(orig) {
return function() {
return xhr.__fileApiXHR ? xhr.__fileApiXHR.abort() : (orig == null ? null : orig.apply(xhr));
}
})(xhr.abort);
xhr.send = function() {
if (arguments[0] != null && arguments[0].__isShim && arguments[0].__setXHR_) {
var formData = arguments[0];
if (arguments[0].__setXHR_) {
var formData = arguments[0];
formData.__setXHR_(xhr);
}
var config = {
url: xhr.__url,
complete: function(err, fileApiXHR) {
Object.defineProperty(xhr, 'status', {get: function() {return fileApiXHR.status}});
Object.defineProperty(xhr, 'statusText', {get: function() {return fileApiXHR.statusText}});
Object.defineProperty(xhr, 'readyState', {get: function() {return 4}});
Object.defineProperty(xhr, 'response', {get: function() {return fileApiXHR.response}});
Object.defineProperty(xhr, 'responseText', {get: function() {return fileApiXHR.responseText}});
xhr.__fileApiXHR = fileApiXHR;
xhr.onreadystatechange();
},
progress: function(e) {
xhr.__progress(e);
},
headers: xhr.__requestHeaders
}
config.data = {};
config.files = {}
for (var i = 0; i < formData.data.length; i++) {
var item = formData.data[i];
if (item.val != null && item.val.name != null && item.val.size != null && item.val.type != null) {
config.files[item.key] = item.val;
} else {
config.data[item.key] = item.val;
}
}
setTimeout(function() {
xhr.__fileApiXHR = FileAPI.upload(config);
}, 1);
} else {
origSend.apply(xhr, arguments);
}
}
return xhr;
}
})(XMLHttpRequest);
}
}
if (!window.FormData) {
var hasFlash = false;
try {
var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
if (fo) hasFlash = true;
} catch(e) {
if (navigator.mimeTypes["application/x-shockwave-flash"] != undefined) hasFlash = true;
}
var wrapFileApi = function(elem) {
if (!elem.__isWrapped && (elem.getAttribute('ng-file-select') != null || elem.getAttribute('data-ng-file-select') != null)) {
var wrap = document.createElement('div');
wrap.innerHTML = '<div class="js-fileapi-wrapper" style="position:relative; overflow:hidden"></div>';
wrap = wrap.firstChild;
var parent = elem.parentNode;
parent.insertBefore(wrap, elem);
parent.removeChild(elem);
wrap.appendChild(elem);
if (!hasFlash) {
wrap.appendChild(document.createTextNode('Flash is required'));
}
elem.__isWrapped = true;
}
};
var changeFnWrapper = function(fn) {
return function(evt) {
var files = FileAPI.getFiles(evt);
if (!evt.target) {
evt.target = {};
}
evt.target.files = files;
evt.target.files.item = function(i) {
return evt.target.files[i] || null;
}
fn(evt);
};
};
var isFileChange = function(elem, e) {
return (e.toLowerCase() === 'change' || e.toLowerCase() === 'onchange') && elem.getAttribute('type') == 'file';
}
if (HTMLInputElement.prototype.addEventListener) {
HTMLInputElement.prototype.addEventListener = (function(origAddEventListener) {
return function(e, fn, b, d) {
if (isFileChange(this, e)) {
wrapFileApi(this);
origAddEventListener.apply(this, [e, changeFnWrapper(fn), b, d]);
} else {
origAddEventListener.apply(this, [e, fn, b, d]);
}
}
})(HTMLInputElement.prototype.addEventListener);
}
if (HTMLInputElement.prototype.attachEvent) {
HTMLInputElement.prototype.attachEvent = (function(origAttachEvent) {
return function(e, fn) {
if (isFileChange(this, e)) {
wrapFileApi(this);
origAttachEvent.apply(this, [e, changeFnWrapper(fn)]);
} else {
origAttachEvent.apply(this, [e, fn]);
}
}
})(HTMLInputElement.prototype.attachEvent);
}
window.FormData = FormData = function() {
return {
append: function(key, val, name) {
this.data.push({
key: key,
val: val,
name: name
});
},
data: [],
__isShim: true
};
};
(function () {
//load FileAPI
if (!window.FileAPI || !FileAPI.upload) {
var base = '', script = document.createElement('script'), allScripts = document.getElementsByTagName('script'), i, index, src;
if (window.FileAPI && window.FileAPI.jsPath) {
base = window.FileAPI.jsPath;
} else {
for (i = 0; i < allScripts.length; i++) {
src = allScripts[i].src;
index = src.indexOf('angular-file-upload-shim.js')
if (index == -1) {
index = src.indexOf('angular-file-upload-shim.min.js');
}
if (index > -1) {
base = src.substring(0, index);
break;
}
}
}
if (!window.FileAPI || FileAPI.staticPath == null) {
FileAPI = {
staticPath: base
}
}
script.setAttribute('src', base + "FileAPI.min.js");
document.getElementsByTagName('head')[0].appendChild(script);
}
})();
}})();
@@ -0,0 +1,2 @@
/*! 1.1.10 */
!function(){if(window.XMLHttpRequest&&(XMLHttpRequest=window.FormData?function(a){return function(){var b=new a;return b.send=function(a){return function(){if(arguments[0]instanceof FormData&&arguments[0].__setXHR_){var c=arguments[0];c.__setXHR_(b)}a.apply(b,arguments)}}(b.send),b}}(XMLHttpRequest):function(a){return function(){var b=new a,c=b.send;return b.__requestHeaders=[],b.open=function(a){return b.upload={addEventListener:function(a,c){"progress"==a&&(b.__progress=c)}},function(c,d,e){a.apply(b,[c,d,e]),b.__url=d}}(b.open),b.getResponseHeader=function(a){return function(c){return b.__fileApiXHR?b.__fileApiXHR.getResponseHeader(c):a.apply(b,[c])}}(b.getResponseHeader),b.getAllResponseHeaders=function(a){return function(){return b.__fileApiXHR?b.__fileApiXHR.getAllResponseHeaders():a.apply(b)}}(b.getAllResponseHeaders),b.abort=function(a){return function(){return b.__fileApiXHR?b.__fileApiXHR.abort():null==a?null:a.apply(b)}}(b.abort),b.send=function(){if(null!=arguments[0]&&arguments[0].__isShim&&arguments[0].__setXHR_){var a=arguments[0];if(arguments[0].__setXHR_){var a=arguments[0];a.__setXHR_(b)}var d={url:b.__url,complete:function(a,c){Object.defineProperty(b,"status",{get:function(){return c.status}}),Object.defineProperty(b,"statusText",{get:function(){return c.statusText}}),Object.defineProperty(b,"readyState",{get:function(){return 4}}),Object.defineProperty(b,"response",{get:function(){return c.response}}),Object.defineProperty(b,"responseText",{get:function(){return c.responseText}}),b.__fileApiXHR=c,b.onreadystatechange()},progress:function(a){b.__progress(a)},headers:b.__requestHeaders};d.data={},d.files={};for(var e=0;e<a.data.length;e++){var f=a.data[e];null!=f.val&&null!=f.val.name&&null!=f.val.size&&null!=f.val.type?d.files[f.key]=f.val:d.data[f.key]=f.val}setTimeout(function(){b.__fileApiXHR=FileAPI.upload(d)},1)}else c.apply(b,arguments)},b}}(XMLHttpRequest)),!window.FormData){var a=!1;try{var b=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");b&&(a=!0)}catch(c){void 0!=navigator.mimeTypes["application/x-shockwave-flash"]&&(a=!0)}var d=function(b){if(!b.__isWrapped&&(null!=b.getAttribute("ng-file-select")||null!=b.getAttribute("data-ng-file-select"))){var c=document.createElement("div");c.innerHTML='<div class="js-fileapi-wrapper" style="position:relative; overflow:hidden"></div>',c=c.firstChild;var d=b.parentNode;d.insertBefore(c,b),d.removeChild(b),c.appendChild(b),a||c.appendChild(document.createTextNode("Flash is required")),b.__isWrapped=!0}},e=function(a){return function(b){var c=FileAPI.getFiles(b);b.target||(b.target={}),b.target.files=c,b.target.files.item=function(a){return b.target.files[a]||null},a(b)}},f=function(a,b){return("change"===b.toLowerCase()||"onchange"===b.toLowerCase())&&"file"==a.getAttribute("type")};HTMLInputElement.prototype.addEventListener&&(HTMLInputElement.prototype.addEventListener=function(a){return function(b,c,g,h){f(this,b)?(d(this),a.apply(this,[b,e(c),g,h])):a.apply(this,[b,c,g,h])}}(HTMLInputElement.prototype.addEventListener)),HTMLInputElement.prototype.attachEvent&&(HTMLInputElement.prototype.attachEvent=function(a){return function(b,c){f(this,b)?(d(this),a.apply(this,[b,e(c)])):a.apply(this,[b,c])}}(HTMLInputElement.prototype.attachEvent)),window.FormData=FormData=function(){return{append:function(a,b,c){this.data.push({key:a,val:b,name:c})},data:[],__isShim:!0}},function(){if(!window.FileAPI||!FileAPI.upload){var a,b,c,d="",e=document.createElement("script"),f=document.getElementsByTagName("script");if(window.FileAPI&&window.FileAPI.jsPath)d=window.FileAPI.jsPath;else for(a=0;a<f.length;a++)if(c=f[a].src,b=c.indexOf("angular-file-upload-shim.js"),-1==b&&(b=c.indexOf("angular-file-upload-shim.min.js")),b>-1){d=c.substring(0,b);break}window.FileAPI&&null!=FileAPI.staticPath||(FileAPI={staticPath:d}),e.setAttribute("src",d+"FileAPI.min.js"),document.getElementsByTagName("head")[0].appendChild(e)}}()}}();
@@ -0,0 +1,156 @@
/**!
* AngularJS file upload/drop directive with http post and progress
* @author Danial <danial.farid@gmail.com>
* @version 1.1.10
*/
(function() {
var angularFileUpload = angular.module('angularFileUpload', []);
angularFileUpload.service('$upload', ['$http', '$rootScope', '$timeout', function($http, $rootScope, $timeout) {
this.upload = function(config) {
config.method = config.method || 'POST';
config.headers = config.headers || {};
config.headers['Content-Type'] = undefined;
config.transformRequest = config.transformRequest || $http.defaults.transformRequest;
var formData = new FormData();
if (config.data) {
for (var key in config.data) {
var val = config.data[key];
if (!config.formDataAppender) {
if (typeof config.transformRequest == 'function') {
val = config.transformRequest(val);
} else {
for (var i = 0; i < config.transformRequest.length; i++) {
var fn = config.transformRequest[i];
if (typeof fn == 'function') {
val = fn(val);
}
}
}
formData.append(key, val);
} else {
config.formDataAppender(formData, key, val);
}
}
}
config.transformRequest = angular.identity;
formData.append(config.fileFormDataName || 'file', config.file, config.file.name);
formData['__setXHR_'] = function(xhr) {
config.__XHR = xhr;
xhr.upload.addEventListener('progress', function(e) {
if (config.progress) {
$timeout(function() {
config.progress(e);
});
}
}, false);
//fix for firefox not firing upload progress end
xhr.upload.addEventListener('load', function(e) {
if (e.lengthComputable) {
$timeout(function() {
config.progress(e);
});
}
}, false);
};
config.data = formData;
var promise = $http(config);
promise.progress = function(fn) {
config.progress = fn;
return promise;
};
promise.abort = function() {
if (config.__XHR) {
$timeout(function() {
config.__XHR.abort();
});
}
return promise;
};
promise.then = (function(promise, origThen) {
return function(s, e, p) {
config.progress = p || config.progress;
origThen.apply(promise, [s, e, p]);
return promise;
};
})(promise, promise.then);
return promise;
};
}]);
angularFileUpload.directive('ngFileSelect', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) {
return function(scope, elem, attr) {
var fn = $parse(attr['ngFileSelect']);
elem.bind('change', function(evt) {
var files = [], fileList, i;
fileList = evt.target.files;
if (fileList != null) {
for (i = 0; i < fileList.length; i++) {
files.push(fileList.item(i));
}
}
$timeout(function() {
fn(scope, {
$files : files,
$event : evt
});
});
});
elem.bind('click', function(){
this.value = null;
});
};
} ]);
angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) {
return function(scope, elem, attr) {
if ('draggable' in document.createElement('span')) {
var fn = $parse(attr['ngFileDropAvailable']);
$timeout(function() {
fn(scope);
});
}
};
} ]);
angularFileUpload.directive('ngFileDrop', [ '$parse', '$http', '$timeout', function($parse, $http, $timeout) {
return function(scope, elem, attr) {
if ('draggable' in document.createElement('span')) {
var fn = $parse(attr['ngFileDrop']);
elem[0].addEventListener("dragover", function(evt) {
evt.stopPropagation();
evt.preventDefault();
elem.addClass(attr['ngFileDragOverClass'] || "dragover");
}, false);
elem[0].addEventListener("dragleave", function(evt) {
elem.removeClass(attr['ngFileDragOverClass'] || "dragover");
}, false);
elem[0].addEventListener("drop", function(evt) {
evt.stopPropagation();
evt.preventDefault();
elem.removeClass(attr['ngFileDragOverClass'] || "dragover");
var files = [], fileList = evt.dataTransfer.files, i;
if (fileList != null) {
for (i = 0; i < fileList.length; i++) {
files.push(fileList.item(i));
}
}
$timeout(function() {
fn(scope, {
$files : files,
$event : evt
});
});
}, false);
}
};
} ]);
})();
@@ -0,0 +1,2 @@
/*! 1.1.10 */
!function(){var a=angular.module("angularFileUpload",[]);a.service("$upload",["$http","$rootScope","$timeout",function(a,b,c){this.upload=function(b){b.method=b.method||"POST",b.headers=b.headers||{},b.headers["Content-Type"]=void 0,b.transformRequest=b.transformRequest||a.defaults.transformRequest;var d=new FormData;if(b.data)for(var e in b.data){var f=b.data[e];if(b.formDataAppender)b.formDataAppender(d,e,f);else{if("function"==typeof b.transformRequest)f=b.transformRequest(f);else for(var g=0;g<b.transformRequest.length;g++){var h=b.transformRequest[g];"function"==typeof h&&(f=h(f))}d.append(e,f)}}b.transformRequest=angular.identity,d.append(b.fileFormDataName||"file",b.file,b.file.name),d.__setXHR_=function(a){b.__XHR=a,a.upload.addEventListener("progress",function(a){b.progress&&c(function(){b.progress(a)})},!1),a.upload.addEventListener("load",function(a){a.lengthComputable&&c(function(){b.progress(a)})},!1)},b.data=d;var i=a(b);return i.progress=function(a){return b.progress=a,i},i.abort=function(){return b.__XHR&&c(function(){b.__XHR.abort()}),i},i.then=function(a,c){return function(d,e,f){return b.progress=f||b.progress,c.apply(a,[d,e,f]),a}}(i,i.then),i}}]),a.directive("ngFileSelect",["$parse","$http","$timeout",function(a,b,c){return function(b,d,e){var f=a(e.ngFileSelect);d.bind("change",function(a){var d,e,g=[];if(d=a.target.files,null!=d)for(e=0;e<d.length;e++)g.push(d.item(e));c(function(){f(b,{$files:g,$event:a})})}),d.bind("click",function(){this.value=null})}}]),a.directive("ngFileDropAvailable",["$parse","$http","$timeout",function(a,b,c){return function(b,d,e){if("draggable"in document.createElement("span")){var f=a(e.ngFileDropAvailable);c(function(){f(b)})}}}]),a.directive("ngFileDrop",["$parse","$http","$timeout",function(a,b,c){return function(b,d,e){if("draggable"in document.createElement("span")){var f=a(e.ngFileDrop);d[0].addEventListener("dragover",function(a){a.stopPropagation(),a.preventDefault(),d.addClass(e.ngFileDragOverClass||"dragover")},!1),d[0].addEventListener("dragleave",function(){d.removeClass(e.ngFileDragOverClass||"dragover")},!1),d[0].addEventListener("drop",function(a){a.stopPropagation(),a.preventDefault(),d.removeClass(e.ngFileDragOverClass||"dragover");var g,h=[],i=a.dataTransfer.files;if(null!=i)for(g=0;g<i.length;g++)h.push(i.item(g));c(function(){f(b,{$files:h,$event:a})})},!1)}}}])}();
@@ -4,19 +4,19 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li class="active">Credentials</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Credentials</h2>
@@ -4,12 +4,12 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-show="!create">
<ul class="rcue-tabs">
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div class="top-nav" data-ng-show="create">
@@ -19,16 +19,16 @@
</div>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li class="active">Add Application</li>
</ol>
<h2 class="pull-left" data-ng-show="create"><span>{{realm.realm}}</span> Add Application</h2>
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li class="active">Settings</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Settings</h2>
@@ -4,12 +4,12 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-show="!create">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div class="top-nav" data-ng-show="create">
@@ -9,19 +9,19 @@
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li class="active">Applications</li>
</ol>
<h2><span>{{realm.realm}}</span> Applications</h2>
<div class="feedback info inline" data-ng-show="!applications || applications.length == 0">
<p><strong>You have not configured applications.</strong> <a class="button" href="#/create/application/{{realm.id}}">Add Application</a></p>
<p><strong>You have not configured applications.</strong> <a class="button" href="#/create/application/{{realm.realm}}">Add Application</a></p>
</div>
<table data-ng-hide="applications.length == 0">
<thead>
<tr>
<th class="rcue-table-actions" colspan="3">
<div class="search-comp clearfix">
<input type="text" placeholder="Search..." class="search"
<input type="text" placeholder="Search..." class="search" data-ng-model="search.name"
onkeyup="if(event.keyCode == 13){$(this).next('button').click();}">
<button class="icon-search" tooltip-placement="right"
tooltip="Search by application name.">
@@ -29,7 +29,7 @@
</button>
</div>
<div class="actions">
<a class="button" href="#/create/application/{{realm.id}}">Add Application</a>
<a class="button" href="#/create/application/{{realm.realm}}">Add Application</a>
</div>
</th>
</tr>
@@ -52,8 +52,8 @@
</tr>
</tfoot>
<tbody>
<tr ng-repeat="app in applications">
<td><a href="#/realms/{{realm.id}}/applications/{{app.id}}">{{app.name}}</a></td>
<tr ng-repeat="app in applications | filter:search">
<td><a href="#/realms/{{realm.realm}}/applications/{{app.name}}">{{app.name}}</a></td>
<td>{{app.enabled}}</td>
<td ng-class="{'text-muted': !app.baseUrl}">{{app.baseUrl || "Not defined"}}</td>
</tr>
@@ -4,30 +4,30 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/installation">Installation</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li class="active">Add role</li>
</ol>
<h2 class="pull-left" data-ng-show="create"><span>{{application.name}}</span> Add Role</h2>
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li class="active">{{role.name}}</li>
</ol>
@@ -4,24 +4,24 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/installation">Installation</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li class="active">Roles</li>
</ol>
<h2><span>{{application.name}}</span> Roles</h2>
<div class="feedback info inline" data-ng-show="!roles || roles.length == 0">
<p><strong>You have not configured application roles.</strong> <a class="button" href="#/create/role/{{realm.id}}/applications/{{application.id}}">Add Role</a></p>
<p><strong>You have not configured application roles.</strong> <a class="button" href="#/create/role/{{realm.realm}}/applications/{{application.name}}">Add Role</a></p>
</div>
<table data-ng-hide="!roles || roles.length == 0">
<caption data-ng-show="roles && roles.length > 0" class="hidden">Table of realm roles</caption>
@@ -29,7 +29,7 @@
<tr>
<th class="rcue-table-actions" colspan="2">
<div class="actions">
<a class="button" href="#/create/role/{{realm.id}}/applications/{{application.id}}">Add Role</a>
<a class="button" href="#/create/role/{{realm.realm}}/applications/{{application.name}}">Add Role</a>
<!-- <button class="remove disabled">Remove</button> -->
</div>
</th>
@@ -64,7 +64,7 @@
</tfoot>
<tbody>
<tr ng-repeat="role in roles">
<td><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles/{{role.id}}">{{role.name}}</a></td>
<td><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles/{{role.name}}">{{role.name}}</a></td>
<td>{{role.description}}</td>
</tr>
</tbody>
@@ -4,19 +4,19 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#">Installation</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}/roles">Roles</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li><a href="#">Sessions</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.id}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li class="active">Scope</li>
</ol>
<h2 class="pull-left"><span>{{application.name}}</span> Scope Mappings</h2>
@@ -0,0 +1,27 @@
<div id="wrapper" class="container">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li class="active">Sessions</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Sessions (Placeholder Page)</h2>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>
@@ -3,16 +3,16 @@
<div class="navbar-inner clearfix container">
<h1><a href="#/"><strong>Keycloak</strong> Central Login</a></h1>
<ul class="nav pull-right" data-ng-hide="auth.loggedIn">
<li><a href="/auth-server/rest/saas/login?path={{fragment}}">Login</a></li>
<li><a href="/auth-server/rest/saas/registrations">Register</a></li>
<li><a href="/auth/rest/admin/login?path={{fragment}}">Login</a></li>
<li><a href="/auth/rest/admin/registrations">Register</a></li>
</ul>
<ul class="nav pull-right" data-ng-show="auth.loggedIn">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span class="icon-user">Icon: user</span>{{auth.user.displayName}}<i class="caret"></i></a>
<ul class="dropdown-menu">
<li><a href="#">Manage Account</a></li>
<li class="separator"><a href="/auth-server/rest/saas/logout">Sign Out</a></li>
<li><a href="/auth/rest/realms/keycloak-admin/account">Manage Account</a></li>
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
</ul>
</li>
</ul>
@@ -25,7 +25,7 @@
<span class="dropdown-label" data-ng-show="showNav()">Realm:</span>
<div class="select-rcue" data-ng-show="showNav()">
<select ng-change="changeRealm()" ng-model="current.realm" ng-options="r.realm for r in current.realms"></select>
</div><a data-ng-click="refresh()" id="refresh" data-ng-show="showNav()" class="tooltipBottomTrigger" data-original-title="Refresh"><span class="icon-spinner6">Icon: spinner</span></a>
</div><a data-ng-click="refresh()" id="refresh" data-ng-show="showNav()" tooltip-placement="bottom" tooltip="Refresh"><span class="icon-spinner6">Icon: spinner</span></a>
</li>
</ul>
<div class="pull-right" data-ng-show="auth.loggedIn">
@@ -35,3 +35,10 @@
</div>
</div>
</div>
<!-- TODO remove once this page is properly styled -->
<style type="text/css">
.icon-spinner6 {
cursor: pointer;
}
</style>
@@ -4,16 +4,17 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li class="active">Credentials</li>
</ol>
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Credentials</h2>
@@ -4,9 +4,10 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-show="!create">
<ul class="rcue-tabs">
<li class="active"><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
</ul>
</div>
<div class="top-nav" data-ng-show="create">
@@ -16,16 +17,16 @@
</div>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
<li class="active">Add OAuth Client</li>
</ol>
<h2 class="pull-left" data-ng-show="create"><span>{{realm.realm}}</span> Add OAuth Client</h2>
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li class="active">Settings</li>
</ol>
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Settings</h2>
@@ -0,0 +1,25 @@
<div id="wrapper" class="container">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-show="!create">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
</ul>
</div>
<div class="top-nav" data-ng-show="create">
<ul class="rcue-tabs">
<li></li>
</ul>
</div>
<div id="content">
<a class="button primary" href="{{download}}" download="keycloak.json" type="submit">Download</a></br>
<textarea style="width: 100%;" rows="20" onclick="this.select()">{{installation | json}}</textarea>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>
@@ -9,12 +9,12 @@
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li class="active">OAuth Clients</li>
</ol>
<h2><span>{{realm.realm}}</span> OAuth Clients</h2>
<div class="feedback info inline" data-ng-show="!oauthClients || oauthClients.length == 0">
<p><strong>You have not configured oauth clients.</strong> <a class="button" href="#/create/oauth-client/{{realm.id}}">Add OAuth Client</a></p>
<p><strong>You have not configured oauth clients.</strong> <a class="button" href="#/create/oauth-client/{{realm.realm}}">Add OAuth Client</a></p>
</div>
<table data-ng-hide="oauthClients.length == 0">
<thead>
@@ -24,12 +24,12 @@
<input type="text" placeholder="Search..." class="search"
onkeyup="if(event.keyCode == 13){$(this).next('button').click();}">
<button class="icon-search" tooltip-placement="right"
tooltip="Search by oauth client name.">
tooltip="Search by oauth client name">
Icon: search
</button>
</div>
<div class="actions">
<a class="button" href="#/create/oauth-client/{{realm.id}}">Add OAuth Client</a>
<a class="button" href="#/create/oauth-client/{{realm.realm}}">Add OAuth Client</a>
</div>
</th>
</tr>
@@ -52,7 +52,7 @@
</tfoot>
<tbody>
<tr ng-repeat="client in oauthClients">
<td><a href="#/realms/{{realm.id}}/oauth-clients/{{client.id}}">{{client.name}}</a></td>
<td><a href="#/realms/{{realm.realm}}/oauth-clients/{{client.id}}">{{client.name}}</a></td>
<td>{{client.enabled}}</td>
</tr>
</tbody>
@@ -4,16 +4,17 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/installation">Installation</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.id}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
<li class="active">Scope</li>
</ol>
<h2 class="pull-left"><span>{{oauth.name}}</span> Scope Mappings</h2>
@@ -1,32 +0,0 @@
<p>Open <a href="https://developers.facebook.com/apps" target="_blank">https://developers.facebook.com/apps</a>. Click on <i>Create New App</i></p>
<p>Use any app name that you'd like, click <i>Continue</i></p>
<p>Select <i>Disabled</i> for <i>Sandbox Mode</i></p>
<p>Under <i>Select how your app integrates with Facebook</i> select <i>Website with Facebook login</i>. Fill in the form with the following values:</p>
<ul>
<li><b>Site URL:</b> {{callbackUrl}}</li>
</ul>
<p>Click on <i>Save changes</i>. Insert <i>App ID</i> and <i>App Secret</i> in the form below.</p>
<form class="form-horizontal" name="fbHelpForm">
<div class="control-group">
<label class="control-label" for="providerHelp.key">App ID </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.key" ng-model="realm.socialProviders[helpPId+'.key']">
</div>
</div>
<div class="control-group">
<label class="control-label" for="providerHelp.secret">App Secret </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.secret" ng-model="realm.socialProviders[helpPId+'.secret']">
</div>
</div>
</form>
<p>
Close the help panel and click <i>save changes</i>.
</p>
@@ -1,36 +0,0 @@
<p>
Open <a href="https://code.google.com/apis/console/" target="_blank">https://code.google.com/apis/console/</a>. From
the
drop-down menu select <i>Create</i>.
</p>
<p>Use any name that you'd like, click <i>Create Project</i>, select <i>API Access</i> and click on <i>Create an OAuth
2.0 client ID</i>.</p>
<p>Use any product name you'd like and leave the other fields empty, then click <i>Next</i>. On the next page select <i>Web
application</i>
as the application type. Click <i>more options</i> next to <i>Your site or hostname</i>. Fill in the form with the
following values:</p>
<ul>
<li><b>Authorized Redirect URIs:</b> {{callbackUrl}}</li>
</ul>
<p>Click on <i>Create client ID</i>. Insert <i>Client ID</i> and <i>Client secret</i> in the form below.</p>
<form class="form-horizontal" name="googleHelpForm">
<div class="control-group">
<label class="control-label" for="providerHelp.key">Client ID </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.key" ng-model="realm.socialProviders[helpPId+'.key']">
</div>
</div>
<div class="control-group">
<label class="control-label" for="providerHelp.secret">Client secret </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.secret" ng-model="realm.socialProviders[helpPId+'.secret']">
</div>
</div>
</form>
<p>Close the help panel and click <i>save changes</i>.</p>
@@ -1,40 +0,0 @@
<p>
Open <a href="https://dev.twitter.com/apps" target="_blank">https://dev.twitter.com/apps</a>. Click on <i>Create a new
application</i>.
</p>
<p>Fill in name, description and website. For <i>Callback URL</i> use the following value:</p>
<ul>
<li><b>Callback URL:</b> {{callbackUrl}}</li>
</ul>
<p>Note: Twitter doesn't allow <b>localhost</b> as domain, use <b>127.0.0.1</b> instead!</p>
<p>Agree to the rules, fill in the captcha and click on <i>Create your Twitter application</i></p>
<p>
Now click on <i>Settings</i> and tick the box <i>Allow this application to be used to Sign in with Twitter</i>, and click on <i>Update
this Twitter application's settings</i>.
</p>
<p>Click on <i>Details</i>. Insert <i>Consumer key</i> and <i>Consumer secret</i> in the form below.</p>
<form class="form-horizontal" name="twitterHelpForm">
<div class="control-group">
<label class="control-label" for="providerHelp.key">Consumer key </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.key" ng-model="realm.socialProviders[helpPId+'.key']">
</div>
</div>
<div class="control-group">
<label class="control-label" for="providerHelp.secret">Consumer secret </label>
<div class="controls">
<input type="text" class="input-xlarge" id="providerHelp.secret" ng-model="realm.socialProviders[helpPId+'.secret']">
</div>
</div>
</form>
<p>
Close the help panel and click <i>save changes</i>.
</p>
@@ -0,0 +1,55 @@
<div id="wrapper" class="container">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div id="content">
<h2 class="pull-left">Add Realm</h2>
<p class="subtitle"><span class="required">*</span> Required fields</p>
<form name="uploadForm" novalidate>
<fieldset>
<legend uncollapsed><span class="text">Import Realm</span></legend>
<div class="form-group clearfix">
<label for="name">Upload JSON File </label>
<div class="controls button-input-file" data-ng-show="!files || files.length == 0">
<a href="#" class="button"><span class="icon-upload">Icon: Upload</span>Choose a JSON File...</a>
<input id="import-file" type="file" class="transparent" ng-file-select="onFileSelect($files)">
</div>
<span class="uploaded-file" data-ng-show="files.length > 0">{{files[0].name}}</span>
<button class="link" data-ng-show="files.length > 0" data-ng-click="changeFileSelect();">Change</button>
</div>
<div class="form-actions inside">
<button type="submit" data-ng-click="uploadFile()" class="primary" data-ng-show="files.length > 0">Upload</button>
</div>
</fieldset>
</form>
<form name="realmForm" novalidate>
<fieldset>
<legend uncollapsed><span class="text">Create Realm</span></legend>
<div class="form-group">
<label for="name">Name <span class="required">*</span></label>
<div class="controls">
<input type="text" id="name" name="name" data-ng-model="realm.realm" autofocus
required>
</div>
</div>
<div class="form-group">
<label for="enabled" class="control-label">Enabled</label>
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
</div>
</fieldset>
<div class="form-actions">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
</button>
<button type="submit" data-ng-click="cancel()">Cancel
</button>
</div>
</form>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>
@@ -1,129 +1,129 @@
<div id="wrapper" class="container realm-policy">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li class="active">Required Credentials</li>
</ol>
<h2><span>{{realm.realm}}</span> Credentials</h2>
<form name="realmForm" novalidate>
<fieldset class="border-top">
<legend uncollapsed><span class="text">Realm Credentials Settings</span></legend>
<div class="form-group clearfix">
<label for="user" class="control-label two-lines">Required User Credentials</label>
<div class="controls">
<input id="user" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredCredentials" placeholder="Type a role and enter">
</div>
</div>
<div class="form-group clearfix">
<label for="application" class="control-label two-lines">Required Application Credentials</label>
<div class="controls">
<input id="application" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredApplicationCredentials" placeholder="Type a role and enter">
</div>
</div>
<div class="form-group clearfix">
<label for="oauth" class="control-label two-lines">Required OAuth Credentials</label>
<div class="controls">
<input id="oauth" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredOAuthClientCredentials" placeholder="Type a role and enter">
</div>
</div>
</fieldset>
<fieldset class="border-top">
<legend uncollapsed><span class="text">Realm Password Policy</span></legend>
<div class="form-group clearfix">
<table>
<caption class="hidden">Table of Password Policies</caption>
<thead>
<tr ng-show="availablePolicies.length > 0">
<th colspan="5" class="rcue-table-actions">
<div class="actions">
<div class="select-rcue">
<select ng-model="newPolicyId"
ng-options="name as name for name in availablePolicies"
placeholder="Please select">
</select>
</div>
<div>
<button ng-click="addPolicy()" ng-disabled="">Add Policy</button>
</div>
</div>
</th>
</tr>
<tr>
<th>Policy Type</th>
<th>Policy Value</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="name in configuredPolicies">
<td>
<div class="clearfix">
<input class="input-small disabled" type="text" value="{{name}}" readonly>
</div>
</td>
<td>
<input ng-model="policy[name]" type="number" placeholder="No value assigned" class="input-small">
</td>
<td>
<div class="action-div"><i class="icon-question" popover="{{policyMessages[name]}}"
popover-placement="left" popover-trigger="mouseenter"></i></div>
<div class="action-div"><i class="icon-remove" ng-click="removePolicy(name)"></i></div>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<div class="form-actions">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
</button>
<button type="submit" kc-reset data-ng-show="changed">Clear changes
</button>
</div>
</form>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>
<!-- TODO remove once this page is properly styled -->
<style type="text/css">
.realm-policy .actions > div {
display: inline-block;
overflow: hidden;
}
.realm-policy td {
font-size: 10px;
}
.realm-policy .action-div {
display: inline-block;
margin: 5px;
}
.realm-policy .icon-remove, .realm-policy .icon-question {
cursor: pointer;
}
<div id="wrapper" class="container realm-policy">
<div class="row">
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Required Credentials</li>
</ol>
<h2><span>{{realm.realm}}</span> Credentials</h2>
<form name="realmForm" novalidate>
<fieldset class="border-top">
<legend uncollapsed><span class="text">Realm Credentials Settings</span></legend>
<div class="form-group clearfix">
<label for="user" class="control-label two-lines">Required User Credentials</label>
<div class="controls">
<input id="user" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredCredentials" placeholder="Type a role and enter">
</div>
</div>
<div class="form-group clearfix">
<label for="application" class="control-label two-lines">Required Application Credentials</label>
<div class="controls">
<input id="application" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredApplicationCredentials" placeholder="Type a role and enter">
</div>
</div>
<div class="form-group clearfix">
<label for="oauth" class="control-label two-lines">Required OAuth Credentials</label>
<div class="controls">
<input id="oauth" type="text" ui-select2="userCredentialOptions" ng-model="realm.requiredOAuthClientCredentials" placeholder="Type a role and enter">
</div>
</div>
</fieldset>
<fieldset class="border-top">
<legend uncollapsed><span class="text">Realm Password Policy</span></legend>
<div class="form-group clearfix">
<table>
<caption class="hidden">Table of Password Policies</caption>
<thead>
<tr ng-show="availablePolicies.length > 0">
<th colspan="5" class="rcue-table-actions">
<div class="actions">
<div class="select-rcue">
<select ng-model="newPolicyId"
ng-options="name as name for name in availablePolicies"
placeholder="Please select">
</select>
</div>
<div>
<button ng-click="addPolicy()" ng-disabled="">Add Policy</button>
</div>
</div>
</th>
</tr>
<tr>
<th>Policy Type</th>
<th>Policy Value</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="name in configuredPolicies">
<td>
<div class="clearfix">
<input class="input-small disabled" type="text" value="{{name}}" readonly>
</div>
</td>
<td>
<input ng-model="policy[name]" type="number" placeholder="No value assigned" class="input-small">
</td>
<td>
<div class="action-div"><i class="icon-question" popover="{{policyMessages[name]}}"
popover-placement="left" popover-trigger="mouseenter"></i></div>
<div class="action-div"><i class="icon-remove" ng-click="removePolicy(name)"></i></div>
</td>
</tr>
</tbody>
</table>
</div>
</fieldset>
<div class="form-actions">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
</button>
<button type="submit" kc-reset data-ng-show="changed">Clear changes
</button>
</div>
</form>
</div>
</div>
<div id="container-right-bg"></div>
</div>
</div>
<!-- TODO remove once this page is properly styled -->
<style type="text/css">
.realm-policy .actions > div {
display: inline-block;
overflow: hidden;
}
.realm-policy td {
font-size: 10px;
}
.realm-policy .action-div {
display: inline-block;
margin: 5px;
}
.realm-policy .icon-remove, .realm-policy .icon-question {
cursor: pointer;
}
</style>
@@ -4,20 +4,20 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Registration</li>
</ol>
<h2><span>{{realm.realm}}</span> Registration Settings</h2>
@@ -36,7 +36,7 @@
</div>
<div class="middle-buttons">
<button type="submit" ng-click="addRealmDefaultRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
<button type="submit" ng-click="rmRealmDefaultRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
<button type="submit" ng-click="deleteRealmDefaultRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
</div>
<div class="select-title">
<label for="assigned">Realm Default Roles</label>
@@ -4,20 +4,20 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li class="active"><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="createRealm">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">General</li>
</ol>
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</h2>
@@ -45,6 +45,10 @@
<label for="social" class="control-label">Social login</label>
<input ng-model="realm.social" name="social" id="social" onoffswitch />
</div>
<div class="form-group clearfix block" data-ng-show="realm.social">
<label for="updateProfileOnInitialSocialLogin" class="control-label">Update profile on first social login</label>
<input ng-model="realm.updateProfileOnInitialSocialLogin" name="updateProfileOnInitialSocialLogin" id="updateProfileOnInitialSocialLogin" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="registrationAllowed" class="control-label">User registration</label>
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
@@ -57,18 +61,10 @@
<label for="verifyEmail" class="control-label">Verify email</label>
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="accountManagement" class="control-label two-lines">User account management</label>
<input ng-model="realm.accountManagement" name="accountManagement" id="accountManagement" onoffswitch />
</div>
<div class="form-group clearfix block">
<label for="requireSsl" class="control-label">Require SSL</label>
<input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
</div>
<div class="form-group">
<label for="cookieLoginAllowed" class="control-label">Cookie login allowed</label>
<input ng-model="realm.cookieLoginAllowed" name="cookieLoginAllowed" id="cookieLoginAllowed" onoffswitch />
</div>
</fieldset>
<div class="form-actions" data-ng-show="createRealm">
@@ -4,20 +4,20 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Keys</li>
</ol>
<h2><span>{{realm.realm}}</span> Keys</h2>
@@ -27,7 +27,8 @@
<label for="publicKey">Public key</label>
<div class="controls">
<textarea type="text" id="publicKey" name="publicKey" class="xlarge" rows="5">{{realm.publicKey}}</textarea>
<textarea type="text" id="publicKey" name="publicKey" class="xlarge" rows="5"
kc-select-action="click" readonly>{{realm.publicKey}}</textarea>
</div>
</div>
</fieldset>
@@ -24,7 +24,7 @@
</tr>
</thead>
<tr data-ng-repeat="r in realms">
<td><a href="#/realms/{{r.id}}">{{r.realm}}</a></td>
<td><a href="#/realms/{{r.realm}}">{{r.realm}}</a></td>
</tr>
</table>
</div>
@@ -1,10 +1,10 @@
<ul data-ng-hide="createRealm">
<li data-ng-class="(!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
<li data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'registration-settings' ||
path[2] == 'keys-settings' || path[2] == 'smtp-settings') && 'active'"><a href="#/realms/{{realm.id}}">Settings</a></li>
<li data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.id}}/users">Users</a>
path[2] == 'keys-settings' || path[2] == 'smtp-settings') && path[3] != 'applications') && 'active'"><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
</li>
<li data-ng-class="(path[2] == 'applications' || path[1] == 'application') && 'active'"><a href="#/realms/{{realm.id}}/applications">Applications</a></li>
<li data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.id}}/oauth-clients">OAuth Clients</a></li>
<li data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
</ul>
@@ -4,23 +4,23 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">SMTP Configuration</li>
</ol>
<h2 class="pull-left"><span>{{realm.realm}}</span> SMTP Settings</h2>
<h2 class="pull-left"><span>{{realm.realm}}</span> Email Server Settings</h2>
<p class="subtitle"><span class="required">*</span> Required fields</p>
<form name="realmForm" novalidate>
<fieldset>
@@ -34,13 +34,13 @@
<div class="form-group clearfix">
<label for="smtpPort" class="control-label">Port <span class="required">*</span></label>
<div class="controls">
<input id="smtpPort" type="text" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)" required>
<input id="smtpPort" type="number" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)" required>
</div>
</div>
<div class="form-group clearfix">
<label for="smtpFrom" class="control-label">From <span class="required">*</span></label>
<div class="controls">
<input id="smtpFrom" type="text" ng-model="realm.smtpServer.from" placeholder="SMTP From" required>
<input id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="Sender Email Address" required>
</div>
</div>
<div class="form-group clearfix">
@@ -53,18 +53,18 @@
</div>
</fieldset>
<fieldset>
<legend collapsed><span class="text">Authentication</span></legend>
<legend uncollapsed><span class="text">Authentication</span></legend>
<div class="form-group clearfix">
<label for="smtpAuth" class="control-label">Enabled</label>
<label for="smtpAuth" class="control-label">Enable Authentication</label>
<input ng-model="realm.smtpServer.auth" name="smtpAuth" id="smtpAuth" onoffswitch />
</div>
<div class="form-group clearfix">
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
<label for="smtpUsername" class="control-label">Username <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
<div class="controls">
<input id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="Login Username" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
</div>
</div>
<div class="form-group clearfix">
<div class="form-group clearfix" data-ng-show="realm.smtpServer.auth">
<label for="smtpPassword" class="control-label">Password <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
<div class="controls">
<input id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="Login Password" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
@@ -4,23 +4,29 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li class="active" data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li class="active" data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Social</li>
</ol>
<h2><span>{{realm.realm}}</span> Social Providers Settings</h2>
<div class="feedback info inline">
<p><strong>Social Callback URL:</strong> {{callbackUrl}}</p>
</div>
<form name="realmForm" novalidate>
<fieldset>
<div>
@@ -64,7 +70,6 @@
ng-class="{'dirty': postSaveProviders.indexOf(pId) > -1}" required>
</td>
<td>
<div class="action-div"><i class="icon-question" ng-click="openHelp(pId)"></i></div>
<div class="action-div"><i class="icon-remove" ng-click="removeProvider(pId)"></i></div>
</td>
</tr>
@@ -72,6 +77,7 @@
</table>
</div>
</fieldset>
<div class="form-actions">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
changes
@@ -86,22 +92,6 @@
</div>
</div>
<div modal="providerHelpModal" close="closeHelp()" options="opts">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3>Configure {{helpPId}}</h3>
</div>
<div class="modal-body">
<div ng-include src="'partials/provider/'+ helpPId +'-help.html'"></div>
</div>
<div class="modal-footer">
<button ng-click="closeHelp()">Close</button>
</div>
</div>
</div>
</div>
<!-- TODO remove once this page is properly styled -->
<style type="text/css">
.social-provider input.ng-invalid.dirty,
@@ -122,4 +112,8 @@
display: inline-block;
margin: 5px;
}
.social-provider .icon-remove, .social-provider .icon-question {
cursor: pointer;
}
</style>
@@ -4,20 +4,20 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav" data-ng-hide="createRealm">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Token</li>
</ol>
<h2><span>{{realm.realm}}</span> Token Settings</h2>
@@ -26,7 +26,7 @@
<div class="form-group input-select">
<label for="tokenLifespan">Token lifespan</label>
<div class="input-group">
<input type="text" data-ng-model="realm.tokenLifespan" id="tokenLifespan" name="tokenLifespan" class="tiny">
<input type="number" required min="1" max="31536000" data-ng-model="realm.tokenLifespan" id="tokenLifespan" name="tokenLifespan" class="tiny">
<div class="select-rcue">
<select name="tokenLifespanUnit" data-ng-model="realm.tokenLifespanUnit" >
<option data-ng-selected="!realm.tokenLifespanUnit">Seconds</option>
@@ -40,7 +40,7 @@
<div class="form-group input-select">
<label for="accessCodeLifespan">Access code lifespan</label>
<div class="input-group">
<input type="text" data-ng-model="realm.accessCodeLifespan" id="accessCodeLifespan" name="accessCodeLifespan" class="tiny">
<input type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespan" id="accessCodeLifespan" name="accessCodeLifespan" class="tiny">
<div class="select-rcue">
<select name="accessCodeLifespanUnit" data-ng-model="realm.accessCodeLifespanUnit">
<option data-ng-selected="!realm.accessCodeLifespanUnit">Seconds</option>
@@ -54,7 +54,7 @@
<div class="form-group input-select">
<label for="accessCodeLifespanUserAction" class="two-lines">Access code user action lifespan</label>
<div class="input-group">
<input type="text" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction" class="tiny">
<input type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction" class="tiny">
<div class="select-rcue">
<select name="accessCodeLifespanUserActionUnit" data-ng-model="realm.accessCodeLifespanUserActionUnit">
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit">Seconds</option>
@@ -4,26 +4,28 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li class="active">{{role.name}}</li>
</ol>
<h2 class="pull-left" data-ng-hide="create"><span>{{realm.realm}}</span> {{role.name}}</h2>
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li class="active">Add Role</li>
</ol>
<h2 class="pull-left" data-ng-show="create"><span>{{realm.realm}}</span> Add Role</h2>
@@ -4,32 +4,32 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
<li data-ng-show="realm.registrationAllowed"><a href="#/realms/{{realm.id}}/registration-settings">Registration</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.id}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
<li><a href="#/realms/{{realm.realm}}">General</a></li>
<li data-ng-show="realm.social"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
<li><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
<li><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">Roles</li>
</ol>
<h2><span>{{realm.realm}}</span> Roles</h2>
<div class="feedback info inline" data-ng-show="!roles || roles.length == 0">
<p><strong>You have not configured realm roles.</strong> <a class="button" href="#/create/role/{{realm.id}}">Add Role</a></p>
<p><strong>You have not configured realm roles.</strong> <a class="button" href="#/create/role/{{realm.realm}}">Add Role</a></p>
</div>
<table data-ng-hide="!roles || roles.length == 0">
<thead>
<tr>
<th class="rcue-table-actions" colspan="2">
<div class="actions">
<a class="button" href="#/create/role/{{realm.id}}">Add Role</a>
<a class="button" href="#/create/role/{{realm.realm}}">Add Role</a>
<!-- <button class="remove disabled">Remove</button> -->
</div>
</th>
@@ -64,7 +64,7 @@
</tfoot>
<tbody>
<tr ng-repeat="role in roles">
<td><a href="#/realms/{{realm.id}}/roles/{{role.id}}">{{role.name}}</a></td>
<td><a href="#/realms/{{realm.realm}}/roles/{{role.name}}">{{role.name}}</a></td>
<td>{{role.description}}</td>
</tr>
</tbody>
@@ -4,16 +4,16 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs" >
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/users">Users</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">{{user.username}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">{{user.username}}</a></li>
<li class="active">Role Mappings</li>
</ol>
<h2 class="pull-left"><span>{{user.username}}'s</span> Role Mappings</h2>
@@ -4,14 +4,14 @@
<div id="content-area" class="col-md-9" role="main">
<div class="top-nav">
<ul class="rcue-tabs">
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
<li class="active"><a href="#/realms/{{realm.id}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li class="active">Users</li>
</ol>
<h2><span>{{user.username}}'s</span> Credentials</h2>
@@ -9,24 +9,24 @@
</div>
<div class="top-nav" data-ng-show="!create">
<ul class="rcue-tabs" >
<li class="active"><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
</ul>
</div>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/users">Users</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
<li class="active">Add</li>
</ol>
<h2 class="pull-left" data-ng-show="create">Add User</h2>
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.id}}/users">Users</a></li>
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">{{user.username}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">{{user.username}}</a></li>
<li class="active">Attributes</li>
</ol>
<h2 class="pull-left" data-ng-hide="create"><span>{{user.username}}'s</span> Attributes</h2>
@@ -36,8 +36,9 @@
<div class="form-group">
<label for="username">Username <span class="required" data-ng-show="create">*</span></label>
<div class="controls">
<!-- Characters >,<,/,\ are forbidden in username -->
<input type="text" id="username" name="username" data-ng-model="user.username" autofocus
required data-ng-readonly="!create">
required ng-pattern="/^[^\<\>\\\/]*$/" data-ng-readonly="!create">
</div>
</div>
@@ -45,7 +46,7 @@
<label for="email" class="control-label">Email</label>
<div class="controls">
<input class="input-small" type="text" name="email" id="email"
<input class="input-small" type="email" name="email" id="email"
data-ng-model="user.email">
</div>
</div>
@@ -9,12 +9,12 @@
</div>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
<li class="active">Users</li>
</ol>
<h2><span>{{realm.realm}}</span> Users</h2>
<table>
<caption data-ng-show="users && search" class="hidden">Table of realm users</caption>
<caption data-ng-show="users" class="hidden">Table of realm users</caption>
<thead>
<tr>
<th class="rcue-table-actions" colspan="4">
@@ -27,8 +27,9 @@
Icon: search
</button>
</div>
<span><span>or</span><button class="link" ng-click="search = null; searchQuery()">View all users</button></span>
<div class="actions">
<a class="button" href="#/create/user/{{realm.id}}">Add User</a>
<a class="button" href="#/create/user/{{realm.realm}}">Add User</a>
</div>
</th>
</tr>
@@ -56,7 +57,7 @@
</tfoot>-->
<tbody>
<tr ng-repeat="user in users">
<td><a href="#/realms/{{realm.id}}/users/{{user.username}}">{{user.username}}</a></td>
<td><a href="#/realms/{{realm.realm}}/users/{{user.username}}">{{user.username}}</a></td>
<td>{{user.lastName}}</td>
<td>{{user.firstName}}</td>
<td>{{user.email}}</td>
@@ -64,9 +65,10 @@
</tbody>
</table>
<div class="feedback warning inline" data-ng-show="searchLoaded && users.length == 0">
<p><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
<p data-ng-show="lastSearch != null"><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
<p data-ng-show="lastSearch == null"><strong>No users present.</strong><br>Create some using the "Add User" button.</p>
</div>
<div class="feedback info inline" data-ng-show="!currentSearch">
<div class="feedback info inline" data-ng-show="!users">
<br/>
<p><strong>Search for users.</strong><br>Please enter a search to display users.</p>
</div>
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0"?>
<project>
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-alpha-1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-core-jaxrs</artifactId>
<name>Keycloak Core JAX-RS</name>
<description/>
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<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>
</plugins>
</build>
</project>
+7 -12
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-alpha-1-12062013</version>
<version>1.0-alpha-1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,23 +14,18 @@
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jose-jwt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,17 +1,7 @@
package org.keycloak;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.util.BasicAuthHelper;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.KeycloakUriBuilder;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import java.security.KeyStore;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
@@ -27,9 +17,9 @@ public class AbstractOAuthClient {
protected KeyStore truststore;
protected String authUrl;
protected String codeUrl;
protected String scope;
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
protected String stateCookiePath;
protected Client client;
protected boolean isSecure;
protected final AtomicLong counter = new AtomicLong();
@@ -37,25 +27,6 @@ public class AbstractOAuthClient {
return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
}
/**
* Creates a Client for obtaining access token from code
*/
public void start() {
if (client == null) {
client = new ResteasyClientBuilder().trustStore(truststore)
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
.connectionPoolSize(10)
.build();
}
}
/**
* closes cllient
*/
public void stop() {
client.close();
}
public String getClientId() {
return clientId;
}
@@ -98,6 +69,14 @@ public class AbstractOAuthClient {
this.codeUrl = codeUrl;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getStateCookieName() {
return stateCookieName;
}
@@ -114,39 +93,8 @@ public class AbstractOAuthClient {
this.stateCookiePath = stateCookiePath;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public String resolveBearerToken(String redirectUri, String code) {
redirectUri = stripOauthParametersFromRedirect(redirectUri);
String authHeader = BasicAuthHelper.createHeader(clientId, password);
Form codeForm = new Form()
.param("grant_type", "authorization_code")
.param("code", code)
.param("client_id", clientId)
.param("password", password)
.param("redirect_uri", redirectUri);
Response res = client.target(codeUrl).request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(codeForm));
try {
if (res.getStatus() == 400) {
throw new BadRequestException();
} else if (res.getStatus() != 200) {
throw new InternalServerErrorException(new Exception("Unknown error when getting acess token"));
}
AccessTokenResponse tokenResponse = res.readEntity(AccessTokenResponse.class);
return tokenResponse.getToken();
} finally {
res.close();
}
}
protected String stripOauthParametersFromRedirect(String uri) {
UriBuilder builder = UriBuilder.fromUri(uri)
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
.replaceQueryParam("code", null)
.replaceQueryParam("state", null);
return builder.build().toString();
@@ -1,8 +1,7 @@
package org.keycloak;
import org.jboss.resteasy.jose.jws.JWSInput;
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.SkeletonKeyToken;
import java.io.IOException;
@@ -13,11 +12,6 @@ import java.security.PublicKey;
* @version $Revision: 1 $
*/
public class RSATokenVerifier {
public static SkeletonKeyToken verifyToken(String tokenString, ResourceMetadata metadata) throws VerificationException {
PublicKey realmKey = metadata.getRealmKey();
String realm = metadata.getRealm();
return verifyToken(tokenString, realmKey, realm);
}
public static SkeletonKeyToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException {
JWSInput input = new JWSInput(tokenString);
@@ -31,14 +25,14 @@ public class RSATokenVerifier {
SkeletonKeyToken token = null;
try {
token = JsonSerialization.fromBytes(SkeletonKeyToken.class, input.getContent());
token = input.readJsonContent(SkeletonKeyToken.class);
} catch (IOException e) {
throw new VerificationException(e);
}
if (!token.isActive()) {
throw new VerificationException("Token is not active.");
}
String user = token.getPrincipal();
String user = token.getSubject();
if (user == null) {
throw new VerificationException("Token user was null");
}
+11
View File
@@ -0,0 +1,11 @@
package org.keycloak;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface ServiceUrlConstants {
public static final String TOKEN_SERVICE_LOGIN_PATH = "/rest/realms/{realm-name}/tokens/login";
public static final String TOKEN_SERVICE_ACCESS_CODE_PATH = "/rest/realms/{realm-name}/tokens/access/codes";
}
@@ -1,5 +1,6 @@
package org.keycloak;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.representations.SkeletonKeyToken;
import java.io.Serializable;
@@ -9,6 +9,7 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class TokenIdGenerator {
private static final AtomicLong counter = new AtomicLong();
public static String generateId() {
return UUID.randomUUID().toString() + "-" + System.currentTimeMillis();
}
@@ -0,0 +1,12 @@
package org.keycloak.adapters;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface AdapterConstants {
// URL endpoints
public static final String K_LOGOUT = "k_logout";
public static final String K_QUERY_BEARER_TOKEN = "k_query_bearer_token";
}
@@ -1,4 +1,4 @@
package org.keycloak;
package org.keycloak.adapters;
import java.security.KeyStore;
import java.security.PublicKey;
@@ -14,6 +14,7 @@ public class ResourceMetadata {
protected String clientKeyPassword;
protected KeyStore truststore;
protected PublicKey realmKey;
protected String scope;
public String getResourceName() {
return resourceName;
@@ -78,4 +79,12 @@ public class ResourceMetadata {
public void setRealmKey(PublicKey realmKey) {
this.realmKey = realmKey;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
@@ -1,252 +0,0 @@
package org.keycloak.adapters.config;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@JsonPropertyOrder({"realm-url", "realm", "resource", "realm-public-key", "admin-role", "auth-url", "code-url", "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", "client-id", "client-credentials"})
public class ManagedResourceConfig {
@JsonProperty("realm-url")
protected String realmUrl;
@JsonProperty("realm")
protected String realm;
@JsonProperty("resource")
protected String resource;
@JsonProperty("realm-public-key")
protected String realmKey;
@JsonProperty("admin-role")
protected String adminRole;
@JsonProperty("auth-url")
protected String authUrl;
@JsonProperty("code-url")
protected String codeUrl;
@JsonProperty("use-resource-role-mappings")
protected boolean useResourceRoleMappings;
@JsonProperty("ssl-not-required")
protected boolean sslNotRequired;
@JsonProperty("allow-any-hostname")
protected boolean allowAnyHostname;
@JsonProperty("disable-trust-manager")
protected boolean disableTrustManager;
@JsonProperty("truststore")
protected String truststore;
@JsonProperty("truststore-password")
protected String truststorePassword;
@JsonProperty("client-keystore")
protected String clientKeystore;
@JsonProperty("client-keystore-password")
protected String clientKeystorePassword;
@JsonProperty("client-key-password")
protected String clientKeyPassword;
@JsonProperty("credentials")
protected Map<String, String> credentials = new HashMap<String, String>();
@JsonProperty("connection-pool-size")
protected int connectionPoolSize;
@JsonProperty("enable-cors")
protected boolean cors;
@JsonProperty("cors-max-age")
protected int corsMaxAge = -1;
@JsonProperty("cors-allowed-headers")
protected String corsAllowedHeaders;
@JsonProperty("cors-allowed-methods")
protected String corsAllowedMethods;
@JsonProperty("expose-token")
protected boolean exposeToken;
@JsonProperty("bearer-only")
protected boolean bearerOnly;
public boolean isUseResourceRoleMappings() {
return useResourceRoleMappings;
}
public void setUseResourceRoleMappings(boolean useResourceRoleMappings) {
this.useResourceRoleMappings = useResourceRoleMappings;
}
public boolean isSslNotRequired() {
return sslNotRequired;
}
public void setSslNotRequired(boolean sslNotRequired) {
this.sslNotRequired = sslNotRequired;
}
public String getRealmUrl() {
return realmUrl;
}
public void setRealmUrl(String realmUrl) {
this.realmUrl = realmUrl;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public String getRealmKey() {
return realmKey;
}
public void setRealmKey(String realmKey) {
this.realmKey = realmKey;
}
public String getAuthUrl() {
return authUrl;
}
public void setAuthUrl(String authUrl) {
this.authUrl = authUrl;
}
public String getCodeUrl() {
return codeUrl;
}
public void setCodeUrl(String codeUrl) {
this.codeUrl = codeUrl;
}
public boolean isAllowAnyHostname() {
return allowAnyHostname;
}
public void setAllowAnyHostname(boolean allowAnyHostname) {
this.allowAnyHostname = allowAnyHostname;
}
public boolean isDisableTrustManager() {
return disableTrustManager;
}
public void setDisableTrustManager(boolean disableTrustManager) {
this.disableTrustManager = disableTrustManager;
}
public String getTruststore() {
return truststore;
}
public void setTruststore(String truststore) {
this.truststore = truststore;
}
public String getTruststorePassword() {
return truststorePassword;
}
public void setTruststorePassword(String truststorePassword) {
this.truststorePassword = truststorePassword;
}
public Map<String, String> getCredentials() {
return credentials;
}
public String getClientKeystore() {
return clientKeystore;
}
public void setClientKeystore(String clientKeystore) {
this.clientKeystore = clientKeystore;
}
public String getClientKeystorePassword() {
return clientKeystorePassword;
}
public void setClientKeystorePassword(String clientKeystorePassword) {
this.clientKeystorePassword = clientKeystorePassword;
}
public String getClientKeyPassword() {
return clientKeyPassword;
}
public void setClientKeyPassword(String clientKeyPassword) {
this.clientKeyPassword = clientKeyPassword;
}
public int getConnectionPoolSize() {
return connectionPoolSize;
}
public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
}
public String getAdminRole() {
return adminRole;
}
public void setAdminRole(String adminRole) {
this.adminRole = adminRole;
}
public boolean isCors() {
return cors;
}
public void setCors(boolean cors) {
this.cors = cors;
}
public int getCorsMaxAge() {
return corsMaxAge;
}
public void setCorsMaxAge(int corsMaxAge) {
this.corsMaxAge = corsMaxAge;
}
public String getCorsAllowedHeaders() {
return corsAllowedHeaders;
}
public void setCorsAllowedHeaders(String corsAllowedHeaders) {
this.corsAllowedHeaders = corsAllowedHeaders;
}
public String getCorsAllowedMethods() {
return corsAllowedMethods;
}
public void setCorsAllowedMethods(String corsAllowedMethods) {
this.corsAllowedMethods = corsAllowedMethods;
}
public boolean isExposeToken() {
return exposeToken;
}
public void setExposeToken(boolean exposeToken) {
this.exposeToken = exposeToken;
}
public boolean isBearerOnly() {
return bearerOnly;
}
public void setBearerOnly(boolean bearerOnly) {
this.bearerOnly = bearerOnly;
}
}
@@ -1,217 +0,0 @@
package org.keycloak.adapters.config;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.EnvUtil;
import org.keycloak.PemUtils;
import org.keycloak.RealmConfiguration;
import org.keycloak.ResourceMetadata;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import javax.ws.rs.core.UriBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PublicKey;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ManagedResourceConfigLoader {
protected ManagedResourceConfig remoteSkeletonKeyConfig;
protected ResourceMetadata resourceMetadata;
protected KeyStore clientCertKeystore;
protected KeyStore truststore;
protected ResteasyClient client;
protected RealmConfiguration realmConfiguration;
public ManagedResourceConfigLoader() {
}
public ManagedResourceConfigLoader(InputStream is) {
loadConfig(is);
}
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
}
public void init(boolean setupClient) {
String truststorePath = remoteSkeletonKeyConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
truststorePath = null;
try {
this.truststore = loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
String clientKeystore = remoteSkeletonKeyConfig.getClientKeystore();
String clientKeyPassword = null;
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = remoteSkeletonKeyConfig.getClientKeystorePassword();
clientCertKeystore = null;
try {
clientCertKeystore = loadKeyStore(clientKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
initClient();
if (remoteSkeletonKeyConfig.getRealmUrl() != null) {
PublishedRealmRepresentation rep = null;
try {
rep = client.target(remoteSkeletonKeyConfig.getRealmUrl()).request().get(PublishedRealmRepresentation.class);
} finally {
if (!setupClient) {
client.close();
}
}
remoteSkeletonKeyConfig.setRealm(rep.getRealm());
remoteSkeletonKeyConfig.setAuthUrl(rep.getAuthorizationUrl());
remoteSkeletonKeyConfig.setCodeUrl(rep.getCodeUrl());
remoteSkeletonKeyConfig.setRealmKey(rep.getPublicKeyPem());
remoteSkeletonKeyConfig.setAdminRole(rep.getAdminRole());
}
if (remoteSkeletonKeyConfig.getAdminRole() == null) {
remoteSkeletonKeyConfig.setAdminRole("$REALM-ADMIN$");
}
String realm = remoteSkeletonKeyConfig.getRealm();
if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String resource = remoteSkeletonKeyConfig.getResource();
if (resource == null) throw new RuntimeException("Must set 'resource' in config");
String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
if (realmKeyPem == null) {
throw new IllegalArgumentException("You must set the realm-public-key");
}
PublicKey realmKey = null;
try {
realmKey = PemUtils.decodePublicKey(realmKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(realm);
resourceMetadata.setResourceName(resource);
resourceMetadata.setRealmKey(realmKey);
resourceMetadata.setClientKeystore(clientCertKeystore);
clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword);
resourceMetadata.setTruststore(this.truststore);
if (!setupClient || remoteSkeletonKeyConfig.isBearerOnly()) return;
realmConfiguration = new RealmConfiguration();
String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
if (authUrl == null) {
throw new RuntimeException("You must specify auth-url");
}
String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl();
if (tokenUrl == null) {
throw new RuntimeException("You mut specify code-url");
}
realmConfiguration.setMetadata(resourceMetadata);
realmConfiguration.setSslRequired(!remoteSkeletonKeyConfig.isSslNotRequired());
for (Map.Entry<String, String> entry : getRemoteSkeletonKeyConfig().getCredentials().entrySet()) {
realmConfiguration.getResourceCredentials().param(entry.getKey(), entry.getValue());
}
ResteasyClient client = getClient();
realmConfiguration.setClient(client);
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
realmConfiguration.setCodeUrl(client.target(tokenUrl));
}
protected void initClient() {
int size = 10;
if (remoteSkeletonKeyConfig.getConnectionPoolSize() > 0)
size = remoteSkeletonKeyConfig.getConnectionPoolSize();
ResteasyClientBuilder.HostnameVerificationPolicy policy = ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (remoteSkeletonKeyConfig.isAllowAnyHostname())
policy = ResteasyClientBuilder.HostnameVerificationPolicy.ANY;
ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(ManagedResourceConfigLoader.class.getClassLoader());
try {
ResteasyProviderFactory.getInstance(); // initialize builtins
RegisterBuiltin.register(providerFactory);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
ResteasyClientBuilder builder = new ResteasyClientBuilder()
.providerFactory(providerFactory)
.connectionPoolSize(size)
.hostnameVerification(policy)
.keyStore(clientCertKeystore, remoteSkeletonKeyConfig.getClientKeyPassword());
if (remoteSkeletonKeyConfig.isDisableTrustManager()) {
builder.disableTrustManager();
} else {
builder.trustStore(truststore);
}
client = builder.build();
}
public ManagedResourceConfig getRemoteSkeletonKeyConfig() {
return remoteSkeletonKeyConfig;
}
public ResourceMetadata getResourceMetadata() {
return resourceMetadata;
}
public ResteasyClient getClient() {
return client;
}
public KeyStore getClientCertKeystore() {
return clientCertKeystore;
}
public KeyStore getTruststore() {
return truststore;
}
public RealmConfiguration getRealmConfiguration() {
return realmConfiguration;
}
protected void loadConfig(InputStream is) {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
remoteSkeletonKeyConfig = null;
try {
remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
+18
View File
@@ -0,0 +1,18 @@
package org.keycloak.jose.jws;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public enum Algorithm {
none,
HS256,
HS384,
HS512,
RS256,
RS384,
RS512,
ES256,
ES384,
ES512
}
+138
View File
@@ -0,0 +1,138 @@
package org.keycloak.jose.jws;
import org.keycloak.jose.jws.crypto.HMACProvider;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.util.Base64Url;
import org.keycloak.util.JsonSerialization;
import javax.crypto.SecretKey;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.PrivateKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JWSBuilder {
String type;
String contentType;
byte[] contentBytes;
public JWSBuilder type(String type) {
this.type = type;
return this;
}
public JWSBuilder contentType(String type) {
this.contentType = type;
return this;
}
public EncodingBuilder content(byte[] bytes) {
this.contentBytes = bytes;
return new EncodingBuilder();
}
public EncodingBuilder jsonContent(Object object) {
try {
this.contentBytes = JsonSerialization.writeValueAsBytes(object);
} catch (IOException e) {
throw new RuntimeException(e);
}
return new EncodingBuilder();
}
protected String encodeHeader(Algorithm alg) {
StringBuilder builder = new StringBuilder("{");
builder.append("\"alg\":\"").append(alg.toString()).append("\"");
if (type != null) builder.append(",\"typ\" : \"").append(type).append("\"");
if (contentType != null) builder.append(",\"cty\":\"").append(contentType).append("\"");
builder.append("}");
try {
return Base64Url.encode(builder.toString().getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
protected String encode(Algorithm alg, byte[] data, byte[] signature) {
StringBuffer encoding = new StringBuffer();
encoding.append(encodeHeader(alg));
encoding.append('.');
encoding.append(Base64Url.encode(data));
encoding.append('.');
if (alg != Algorithm.none) {
encoding.append(Base64Url.encode(signature));
}
return encoding.toString();
}
protected byte[] marshalContent() {
return contentBytes;
}
public class EncodingBuilder {
public String none() {
byte[] data = marshalContent();
return encode(Algorithm.none, data, null);
}
public String rsa256(PrivateKey privateKey) {
byte[] data = marshalContent();
byte[] signature = RSAProvider.sign(data, Algorithm.RS256, privateKey);
return encode(Algorithm.RS256, data, signature);
}
public String rsa384(PrivateKey privateKey) {
byte[] data = marshalContent();
byte[] signature = RSAProvider.sign(data, Algorithm.RS384, privateKey);
return encode(Algorithm.RS384, data, signature);
}
public String rsa512(PrivateKey privateKey) {
byte[] data = marshalContent();
byte[] signature = RSAProvider.sign(data, Algorithm.RS512, privateKey);
return encode(Algorithm.RS512, data, signature);
}
public String hmac256(byte[] sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret);
return encode(Algorithm.HS256, data, signature);
}
public String hmac384(byte[] sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret);
return encode(Algorithm.HS384, data, signature);
}
public String hmac512(byte[] sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret);
return encode(Algorithm.HS512, data, signature);
}
public String hmac256(SecretKey sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret);
return encode(Algorithm.HS256, data, signature);
}
public String hmac384(SecretKey sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret);
return encode(Algorithm.HS384, data, signature);
}
public String hmac512(SecretKey sharedSecret) {
byte[] data = marshalContent();
byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret);
return encode(Algorithm.HS512, data, signature);
}
}
}
+64
View File
@@ -0,0 +1,64 @@
package org.keycloak.jose.jws;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import java.io.IOException;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JWSHeader implements Serializable {
@JsonProperty("alg")
private Algorithm algorithm;
@JsonProperty("typ")
private String type;
@JsonProperty("cty")
private String contentType;
public JWSHeader() {
}
public JWSHeader(Algorithm algorithm, String type, String contentType) {
this.algorithm = algorithm;
this.type = type;
this.contentType = contentType;
}
public Algorithm getAlgorithm() {
return algorithm;
}
public String getType() {
return type;
}
public String getContentType() {
return contentType;
}
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
}
public String toString() {
try {
return mapper.writeValueAsString(this);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
+82
View File
@@ -0,0 +1,82 @@
package org.keycloak.jose.jws;
import org.keycloak.util.Base64Url;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JWSInput {
String wireString;
String encodedHeader;
String encodedContent;
String encodedSignature;
JWSHeader header;
byte[] content;
byte[] signature;
public JWSInput(String wire) {
this.wireString = wire;
String[] parts = wire.split("\\.");
if (parts.length < 2 || parts.length > 3) throw new IllegalArgumentException("Parsing error");
encodedHeader = parts[0];
encodedContent = parts[1];
try {
content = Base64Url.decode(encodedContent);
if (parts.length > 2) {
encodedSignature = parts[2];
signature = Base64Url.decode(encodedSignature);
}
byte[] headerBytes = Base64Url.decode(encodedHeader);
header = JsonSerialization.readValue(headerBytes, JWSHeader.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String getWireString() {
return wireString;
}
public String getEncodedHeader() {
return encodedHeader;
}
public String getEncodedContent() {
return encodedContent;
}
public String getEncodedSignature() {
return encodedSignature;
}
public JWSHeader getHeader() {
return header;
}
public byte[] getContent() {
return content;
}
public byte[] getSignature() {
return signature;
}
public <T> T readJsonContent(Class<T> type) throws IOException {
return JsonSerialization.readValue(content, type);
}
public String readContentAsString() {
try {
return new String(content, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,86 @@
package org.keycloak.jose.jws.crypto;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.util.Base64Url;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class HMACProvider {
public static String getJavaAlgorithm(Algorithm alg) {
switch (alg) {
case HS256:
return "HMACSHA256";
case HS384:
return "HMACSHA384";
case HS512:
return "HMACSHA512";
default:
throw new IllegalArgumentException("Not a MAC Algorithm");
}
}
public static Mac getMAC(final Algorithm alg) {
try {
return Mac.getInstance(getJavaAlgorithm(alg));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Unsupported HMAC algorithm: " + e.getMessage(), e);
}
}
public static byte[] sign(byte[] data, Algorithm algorithm, byte[] sharedSecret) {
try {
Mac mac = getMAC(algorithm);
mac.init(new SecretKeySpec(sharedSecret, mac.getAlgorithm()));
mac.update(data);
return mac.doFinal();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static byte[] sign(byte[] data, Algorithm algorithm, SecretKey key) {
try {
Mac mac = getMAC(algorithm);
mac.init(key);
mac.update(data);
return mac.doFinal();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static boolean verify(JWSInput input, SecretKey key) {
try {
byte[] signature = sign(input.getContent(), input.getHeader().getAlgorithm(), key);
String x = Base64Url.encode(signature);
return x.equals(input.getEncodedSignature());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static boolean verify(JWSInput input, byte[] sharedSecret) {
try {
byte[] signature = sign(input.getContent(), input.getHeader().getAlgorithm(), sharedSecret);
String x = Base64Url.encode(signature);
return x.equals(input.getEncodedSignature());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,61 @@
package org.keycloak.jose.jws.crypto;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.JWSInput;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RSAProvider {
public static String getJavaAlgorithm(Algorithm alg) {
switch (alg) {
case RS256:
return "SHA256withRSA";
case RS384:
return "SHA384withRSA";
case RS512:
return "SHA512withRSA";
default:
throw new IllegalArgumentException("Not an RSA Algorithm");
}
}
public static Signature getSignature(Algorithm alg) {
try {
return Signature.getInstance(getJavaAlgorithm(alg));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static byte[] sign(byte[] data, Algorithm algorithm, PrivateKey privateKey) {
try {
Signature signature = getSignature(algorithm);
signature.initSign(privateKey);
signature.update(data);
return signature.sign();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static boolean verify(JWSInput input, PublicKey publicKey) {
try {
Signature verifier = getSignature(input.getHeader().getAlgorithm());
verifier.initVerify(publicKey);
verifier.update(input.getContent());
return verifier.verify(input.getSignature());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,136 @@
package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JsonWebToken implements Serializable {
@JsonProperty("jti")
protected String id;
@JsonProperty("exp")
protected long expiration;
@JsonProperty("nbf")
protected long notBefore;
@JsonProperty("iat")
protected long issuedAt;
@JsonProperty("iss")
protected String issuer;
@JsonProperty("aud")
protected String audience;
@JsonProperty("sub")
protected String subject;
@JsonProperty("typ")
protected String type;
public String getId() {
return id;
}
public JsonWebToken id(String id) {
this.id = id;
return this;
}
public long getExpiration() {
return expiration;
}
public JsonWebToken expiration(long expiration) {
this.expiration = expiration;
return this;
}
@JsonIgnore
public boolean isExpired() {
long time = System.currentTimeMillis() / 1000;
return time > expiration;
}
public long getNotBefore() {
return notBefore;
}
public JsonWebToken notBefore(long notBefore) {
this.notBefore = notBefore;
return this;
}
@JsonIgnore
public boolean isNotBefore() {
return (System.currentTimeMillis() / 1000) >= notBefore;
}
/**
* Tests that the token is not expired and is not-before.
*
* @return
*/
@JsonIgnore
public boolean isActive() {
return (!isExpired() || expiration == 0) && (isNotBefore() || notBefore == 0);
}
public long getIssuedAt() {
return issuedAt;
}
/**
* Set issuedAt to the current time
*/
@JsonIgnore
public JsonWebToken issuedNow() {
issuedAt = System.currentTimeMillis() / 1000;
return this;
}
public JsonWebToken issuedAt(long issuedAt) {
this.issuedAt = issuedAt;
return this;
}
public String getIssuer() {
return issuer;
}
public JsonWebToken issuer(String issuer) {
this.issuer = issuer;
return this;
}
public String getAudience() {
return audience;
}
public JsonWebToken audience(String audience) {
this.audience = audience;
return this;
}
public String getSubject() {
return subject;
}
public JsonWebToken principal(String principal) {
this.subject = principal;
return this;
}
public String getType() {
return type;
}
public JsonWebToken type(String type) {
this.type = type;
return this;
}
}
@@ -1,6 +1,7 @@
package org.keycloak.representations;
import javax.ws.rs.core.MultivaluedHashMap;
import org.keycloak.util.MultivaluedHashMap;
/**
* Key is resource desired. Values are roles desired for that resource
@@ -2,7 +2,6 @@ package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.jboss.resteasy.jwt.JsonWebToken;
import java.util.HashMap;
import java.util.HashSet;
@@ -1,4 +1,4 @@
package org.keycloak.representations.idm.admin;
package org.keycloak.representations.adapters.action;
import org.codehaus.jackson.annotate.JsonIgnore;
@@ -12,16 +12,14 @@ public class AdminAction {
protected String id;
protected long expiration;
protected String resource;
protected String action;
public AdminAction() {
}
public AdminAction(String id, long expiration, String resource, String action) {
public AdminAction(String id, long expiration, String resource) {
this.id = id;
this.expiration = expiration;
this.resource = resource;
this.action = action;
}
public String getId() {
@@ -32,17 +30,8 @@ public class AdminAction {
this.id = id;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@JsonIgnore
public boolean isExpired()
{
public boolean isExpired() {
long time = System.currentTimeMillis() / 1000;
return time > expiration;
}
@@ -1,18 +1,17 @@
package org.keycloak.representations.idm.admin;
package org.keycloak.representations.adapters.action;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LogoutAction extends AdminAction {
public static final String LOGOUT_ACTION = "logout";
protected String user;
public LogoutAction() {
}
public LogoutAction(String id, long expiration, String resource, String user) {
super(id, expiration, resource, LOGOUT_ACTION);
super(id, expiration, resource);
this.user = user;
}
@@ -0,0 +1,104 @@
package org.keycloak.representations.adapters.config;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
/**
* Configuration for Java based adapters
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
"resource", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
"expose-token", "bearer-only", "scope",
"connection-pool-size",
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
"client-keystore", "client-keystore-password", "client-key-password"
})
public class AdapterConfig extends BaseAdapterConfig {
@JsonProperty("allow-any-hostname")
protected boolean allowAnyHostname;
@JsonProperty("disable-trust-manager")
protected boolean disableTrustManager;
@JsonProperty("truststore")
protected String truststore;
@JsonProperty("truststore-password")
protected String truststorePassword;
@JsonProperty("client-keystore")
protected String clientKeystore;
@JsonProperty("client-keystore-password")
protected String clientKeystorePassword;
@JsonProperty("client-key-password")
protected String clientKeyPassword;
@JsonProperty("connection-pool-size")
protected int connectionPoolSize = 20;
public boolean isAllowAnyHostname() {
return allowAnyHostname;
}
public void setAllowAnyHostname(boolean allowAnyHostname) {
this.allowAnyHostname = allowAnyHostname;
}
public boolean isDisableTrustManager() {
return disableTrustManager;
}
public void setDisableTrustManager(boolean disableTrustManager) {
this.disableTrustManager = disableTrustManager;
}
public String getTruststore() {
return truststore;
}
public void setTruststore(String truststore) {
this.truststore = truststore;
}
public String getTruststorePassword() {
return truststorePassword;
}
public void setTruststorePassword(String truststorePassword) {
this.truststorePassword = truststorePassword;
}
public String getClientKeystore() {
return clientKeystore;
}
public void setClientKeystore(String clientKeystore) {
this.clientKeystore = clientKeystore;
}
public String getClientKeystorePassword() {
return clientKeystorePassword;
}
public void setClientKeystorePassword(String clientKeystorePassword) {
this.clientKeystorePassword = clientKeystorePassword;
}
public String getClientKeyPassword() {
return clientKeyPassword;
}
public void setClientKeyPassword(String clientKeyPassword) {
this.clientKeyPassword = clientKeyPassword;
}
public int getConnectionPoolSize() {
return connectionPoolSize;
}
public void setConnectionPoolSize(int connectionPoolSize) {
this.connectionPoolSize = connectionPoolSize;
}
}
@@ -0,0 +1,123 @@
package org.keycloak.representations.adapters.config;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
import org.keycloak.representations.SkeletonKeyScope;
import java.util.HashMap;
import java.util.Map;
/**
* Common Adapter configuration
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
"resource", "credentials",
"use-resource-role-mappings",
"enable-cors", "cors-max-age", "cors-allowed-methods",
"expose-token", "bearer-only", "scope"})
public class BaseAdapterConfig extends BaseRealmConfig {
@JsonProperty("resource")
protected String resource;
@JsonProperty("use-resource-role-mappings")
protected boolean useResourceRoleMappings;
@JsonProperty("enable-cors")
protected boolean cors;
@JsonProperty("cors-max-age")
protected int corsMaxAge = -1;
@JsonProperty("cors-allowed-headers")
protected String corsAllowedHeaders;
@JsonProperty("cors-allowed-methods")
protected String corsAllowedMethods;
@JsonProperty("expose-token")
protected boolean exposeToken;
@JsonProperty("bearer-only")
protected boolean bearerOnly;
@JsonProperty("credentials")
protected Map<String, String> credentials = new HashMap<String, String>();
@JsonProperty("scope")
protected SkeletonKeyScope scope;
public boolean isUseResourceRoleMappings() {
return useResourceRoleMappings;
}
public void setUseResourceRoleMappings(boolean useResourceRoleMappings) {
this.useResourceRoleMappings = useResourceRoleMappings;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public boolean isCors() {
return cors;
}
public void setCors(boolean cors) {
this.cors = cors;
}
public int getCorsMaxAge() {
return corsMaxAge;
}
public void setCorsMaxAge(int corsMaxAge) {
this.corsMaxAge = corsMaxAge;
}
public String getCorsAllowedHeaders() {
return corsAllowedHeaders;
}
public void setCorsAllowedHeaders(String corsAllowedHeaders) {
this.corsAllowedHeaders = corsAllowedHeaders;
}
public String getCorsAllowedMethods() {
return corsAllowedMethods;
}
public void setCorsAllowedMethods(String corsAllowedMethods) {
this.corsAllowedMethods = corsAllowedMethods;
}
public boolean isExposeToken() {
return exposeToken;
}
public void setExposeToken(boolean exposeToken) {
this.exposeToken = exposeToken;
}
public boolean isBearerOnly() {
return bearerOnly;
}
public void setBearerOnly(boolean bearerOnly) {
this.bearerOnly = bearerOnly;
}
public Map<String, String> getCredentials() {
return credentials;
}
public void setCredentials(Map<String, String> credentials) {
this.credentials = credentials;
}
public SkeletonKeyScope getScope() {
return scope;
}
public void setScope(SkeletonKeyScope scope) {
this.scope = scope;
}
}
@@ -0,0 +1,54 @@
package org.keycloak.representations.adapters.config;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.annotate.JsonPropertyOrder;
/**
* Common Realm Configuration
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required"})
public class BaseRealmConfig {
@JsonProperty("realm")
protected String realm;
@JsonProperty("realm-public-key")
protected String realmKey;
@JsonProperty("auth-server-url")
protected String authServerUrl;
@JsonProperty("ssl-not-required")
protected boolean sslNotRequired;
public boolean isSslNotRequired() {
return sslNotRequired;
}
public void setSslNotRequired(boolean sslNotRequired) {
this.sslNotRequired = sslNotRequired;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getRealmKey() {
return realmKey;
}
public void setRealmKey(String realmKey) {
this.realmKey = realmKey;
}
public String getAuthServerUrl() {
return authServerUrl;
}
public void setAuthServerUrl(String authServerUrl) {
this.authServerUrl = authServerUrl;
}
}
@@ -1,80 +0,0 @@
package org.keycloak.representations.idm;
import org.codehaus.jackson.annotate.JsonProperty;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ApplicationInstallationRepresentation {
protected String realm;
protected String resource;
@JsonProperty("realm-public-key")
protected String realmPublicKey;
@JsonProperty("auth-url")
protected String authUrl;
@JsonProperty("code-url")
protected String codeUrl;
@JsonProperty("ssl-not-required")
protected boolean sslNotRequired;
protected Map<String, String> credentials;
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public String getRealmPublicKey() {
return realmPublicKey;
}
public void setRealmPublicKey(String realmPublicKey) {
this.realmPublicKey = realmPublicKey;
}
public String getAuthUrl() {
return authUrl;
}
public void setAuthUrl(String authUrl) {
this.authUrl = authUrl;
}
public String getCodeUrl() {
return codeUrl;
}
public void setCodeUrl(String codeUrl) {
this.codeUrl = codeUrl;
}
public boolean isSslNotRequired() {
return sslNotRequired;
}
public void setSslNotRequired(boolean sslNotRequired) {
this.sslNotRequired = sslNotRequired;
}
public Map<String, String> getCredentials() {
return credentials;
}
public void setCredentials(Map<String, String> credentials) {
this.credentials = credentials;
}
}
@@ -1,9 +1,9 @@
package org.keycloak.representations.idm;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CredentialRepresentation {
public static final String PASSWORD = "password";
public static final String TOTP = "totp";
@@ -19,7 +19,7 @@ public class MappingsRepresentation {
this.realmMappings = realmMappings;
}
public Map<String,ApplicationMappingsRepresentation> getApplicationMappings() {
public Map<String, ApplicationMappingsRepresentation> getApplicationMappings() {
return applicationMappings;
}
@@ -1,6 +1,5 @@
package org.keycloak.representations.idm;
import java.util.ArrayList;
import java.util.List;
/**
@@ -3,7 +3,7 @@ package org.keycloak.representations.idm;
import org.bouncycastle.openssl.PEMWriter;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.keycloak.PemUtils;
import org.keycloak.util.PemUtils;
import java.io.IOException;
import java.io.StringWriter;
@@ -17,14 +17,12 @@ public class RealmRepresentation {
protected Integer accessCodeLifespan;
protected Integer accessCodeLifespanUserAction;
protected Boolean enabled;
protected Boolean accountManagement;
protected Boolean sslNotRequired;
protected Boolean cookieLoginAllowed;
protected Boolean registrationAllowed;
protected Boolean verifyEmail;
protected Boolean resetPasswordAllowed;
protected Boolean social;
protected Boolean automaticRegistrationAfterSocialLogin;
protected Boolean updateProfileOnInitialSocialLogin;
protected String privateKey;
protected String publicKey;
protected List<RoleRepresentation> roles;
@@ -108,14 +106,6 @@ public class RealmRepresentation {
this.enabled = enabled;
}
public Boolean getAccountManagement() {
return accountManagement;
}
public void setAccountManagement(Boolean accountManagement) {
this.accountManagement = accountManagement;
}
public Boolean isSslNotRequired() {
return sslNotRequired;
}
@@ -124,14 +114,6 @@ public class RealmRepresentation {
this.sslNotRequired = sslNotRequired;
}
public Boolean isCookieLoginAllowed() {
return cookieLoginAllowed;
}
public void setCookieLoginAllowed(Boolean cookieLoginAllowed) {
this.cookieLoginAllowed = cookieLoginAllowed;
}
public Integer getTokenLifespan() {
return tokenLifespan;
}
@@ -288,12 +270,12 @@ public class RealmRepresentation {
this.social = social;
}
public Boolean isAutomaticRegistrationAfterSocialLogin() {
return automaticRegistrationAfterSocialLogin;
public Boolean isUpdateProfileOnInitialSocialLogin() {
return updateProfileOnInitialSocialLogin;
}
public void setAutomaticRegistrationAfterSocialLogin(Boolean automaticRegistrationAfterSocialLogin) {
this.automaticRegistrationAfterSocialLogin = automaticRegistrationAfterSocialLogin;
public void setUpdateProfileOnInitialSocialLogin(Boolean updateProfileOnInitialSocialLogin) {
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
}
public Map<String, String> getSocialProviders() {
File diff suppressed because it is too large. Load diff
+42
View File
@@ -0,0 +1,42 @@
package org.keycloak.util;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Base64Url {
public static String encode(byte[] bytes) {
String s = Base64.encodeBytes(bytes);
s = s.split("=")[0]; // Remove any trailing '='s
s = s.replace('+', '-'); // 62nd char of encoding
s = s.replace('/', '_'); // 63rd char of encoding
return s;
}
public static byte[] decode(String s) {
s = s.replace('-', '+'); // 62nd char of encoding
s = s.replace('_', '/'); // 63rd char of encoding
switch (s.length() % 4) // Pad with trailing '='s
{
case 0:
break; // No pad chars in this case
case 2:
s += "==";
break; // Two pad chars
case 3:
s += "=";
break; // One pad char
default:
throw new RuntimeException(
"Illegal base64url string!");
}
try {
return Base64.decode(s);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -1,4 +1,4 @@
package org.keycloak;
package org.keycloak.util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -1,4 +1,4 @@
package org.keycloak;
package org.keycloak.util;
import java.io.DataInputStream;
import java.io.InputStream;
+526
View File
@@ -0,0 +1,526 @@
package org.keycloak.util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Encode
{
private static final String UTF_8 = "UTF-8";
private static final Pattern PARAM_REPLACEMENT = Pattern.compile("_resteasy_uri_parameter");
private static final String[] pathEncoding = new String[128];
private static final String[] pathSegmentEncoding = new String[128];
private static final String[] matrixParameterEncoding = new String[128];
private static final String[] queryNameValueEncoding = new String[128];
private static final String[] queryStringEncoding = new String[128];
static
{
/*
* Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>. PCHAR is allowed allong with '/'
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*
*/
for (int i = 0; i < 128; i++)
{
if (i >= 'a' && i <= 'z') continue;
if (i >= 'A' && i <= 'Z') continue;
if (i >= '0' && i <= '9') continue;
switch ((char) i)
{
case '-':
case '.':
case '_':
case '~':
case '!':
case '$':
case '&':
case '\'':
case '(':
case ')':
case '*':
case '+':
case ',':
case '/':
case ';':
case '=':
case ':':
case '@':
continue;
}
StringBuffer sb = new StringBuffer();
sb.append((char) i);
pathEncoding[i] = URLEncoder.encode(sb.toString());
}
pathEncoding[' '] = "%20";
System.arraycopy(pathEncoding, 0, matrixParameterEncoding, 0, pathEncoding.length);
matrixParameterEncoding[';'] = "%3B";
matrixParameterEncoding['='] = "%3D";
matrixParameterEncoding['/'] = "%2F"; // RESTEASY-729
System.arraycopy(pathEncoding, 0, pathSegmentEncoding, 0, pathEncoding.length);
pathSegmentEncoding['/'] = "%2F";
/*
* Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* space encoded as '+'
*
*/
for (int i = 0; i < 128; i++)
{
if (i >= 'a' && i <= 'z') continue;
if (i >= 'A' && i <= 'Z') continue;
if (i >= '0' && i <= '9') continue;
switch ((char) i)
{
case '-':
case '.':
case '_':
case '~':
case '?':
continue;
case ' ':
queryNameValueEncoding[i] = "+";
continue;
}
StringBuffer sb = new StringBuffer();
sb.append((char) i);
queryNameValueEncoding[i] = URLEncoder.encode(sb.toString());
}
/*
* query = *( pchar / "/" / "?" )
*/
for (int i = 0; i < 128; i++)
{
if (i >= 'a' && i <= 'z') continue;
if (i >= 'A' && i <= 'Z') continue;
if (i >= '0' && i <= '9') continue;
switch ((char) i)
{
case '-':
case '.':
case '_':
case '~':
case '!':
case '$':
case '&':
case '\'':
case '(':
case ')':
case '*':
case '+':
case ',':
case ';':
case '=':
case ':':
case '@':
case '?':
case '/':
continue;
case ' ':
queryStringEncoding[i] = "%20";
continue;
}
StringBuffer sb = new StringBuffer();
sb.append((char) i);
queryStringEncoding[i] = URLEncoder.encode(sb.toString());
}
}
/**
* Keep encoded values "%..." and template parameters intact.
*/
public static String encodeQueryString(String value)
{
return encodeValue(value, queryStringEncoding);
}
/**
* Keep encoded values "%...", matrix parameters, template parameters, and '/' characters intact.
*/
public static String encodePath(String value)
{
return encodeValue(value, pathEncoding);
}
/**
* Keep encoded values "%...", matrix parameters and template parameters intact.
*/
public static String encodePathSegment(String value)
{
return encodeValue(value, pathSegmentEncoding);
}
/**
* Keep encoded values "%..." and template parameters intact.
*/
public static String encodeFragment(String value)
{
return encodeValue(value, queryNameValueEncoding);
}
/**
* Keep encoded values "%..." and template parameters intact.
*/
public static String encodeMatrixParam(String value)
{
return encodeValue(value, matrixParameterEncoding);
}
/**
* Keep encoded values "%..." and template parameters intact.
*/
public static String encodeQueryParam(String value)
{
return encodeValue(value, queryNameValueEncoding);
}
//private static final Pattern nonCodes = Pattern.compile("%([^a-fA-F0-9]|$)");
private static final Pattern nonCodes = Pattern.compile("%([^a-fA-F0-9]|[a-fA-F0-9]$|$|[a-fA-F0-9][^a-fA-F0-9])");
private static final Pattern encodedChars = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])");
private static final Pattern encodedCharsMulti = Pattern.compile("((%[a-fA-F0-9][a-fA-F0-9])+)");
public static String decodePath(String path)
{
Matcher matcher = encodedCharsMulti.matcher(path);
StringBuffer buf = new StringBuffer();
CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();
while (matcher.find())
{
decoder.reset();
String decoded = decodeBytes(matcher.group(1), decoder);
decoded = decoded.replace("\\", "\\\\");
decoded = decoded.replace("$", "\\$");
matcher.appendReplacement(buf, decoded);
}
matcher.appendTail(buf);
return buf.toString();
}
private static String decodeBytes(String enc, CharsetDecoder decoder)
{
Matcher matcher = encodedChars.matcher(enc);
StringBuffer buf = new StringBuffer();
ByteBuffer bytes = ByteBuffer.allocate(enc.length() / 3);
while (matcher.find())
{
int b = Integer.parseInt(matcher.group(1), 16);
bytes.put((byte) b);
}
bytes.flip();
try
{
return decoder.decode(bytes).toString();
}
catch (CharacterCodingException e)
{
throw new RuntimeException(e);
}
}
/**
* Encode '%' if it is not an encoding sequence
*
* @param string
* @return
*/
public static String encodeNonCodes(String string)
{
Matcher matcher = nonCodes.matcher(string);
StringBuffer buf = new StringBuffer();
// FYI: we do not use the no-arg matcher.find()
// coupled with matcher.appendReplacement()
// because the matched text may contain
// a second % and we must make sure we
// encode it (if necessary).
int idx = 0;
while (matcher.find(idx))
{
int start = matcher.start();
buf.append(string.substring(idx, start));
buf.append("%25");
idx = start + 1;
}
buf.append(string.substring(idx));
return buf.toString();
}
public static boolean savePathParams(String segment, StringBuffer newSegment, List<String> params)
{
boolean foundParam = false;
// Regular expressions can have '{' and '}' characters. Replace them to do match
segment = PathHelper.replaceEnclosedCurlyBraces(segment);
Matcher matcher = PathHelper.URI_TEMPLATE_PATTERN.matcher(segment);
while (matcher.find())
{
foundParam = true;
String group = matcher.group();
// Regular expressions can have '{' and '}' characters. Recover earlier replacement
params.add(PathHelper.recoverEnclosedCurlyBraces(group));
matcher.appendReplacement(newSegment, "_resteasy_uri_parameter");
}
matcher.appendTail(newSegment);
return foundParam;
}
/**
* Keep encoded values "%..." and template parameters intact i.e. "{x}"
*
* @param segment
* @param encoding
* @return
*/
public static String encodeValue(String segment, String[] encoding)
{
ArrayList<String> params = new ArrayList<String>();
boolean foundParam = false;
StringBuffer newSegment = new StringBuffer();
if (savePathParams(segment, newSegment, params))
{
foundParam = true;
segment = newSegment.toString();
}
String result = encodeFromArray(segment, encoding, false);
result = encodeNonCodes(result);
segment = result;
if (foundParam)
{
segment = pathParamReplacement(segment, params);
}
return segment;
}
/**
* Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>. PCHAR is allowed allong with '/'
* <p/>
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*/
public static String encodePathAsIs(String segment)
{
return encodeFromArray(segment, pathEncoding, true);
}
/**
* Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
*
* @param segment
* @return
*/
public static String encodePathSaveEncodings(String segment)
{
String result = encodeFromArray(segment, pathEncoding, false);
result = encodeNonCodes(result);
return result;
}
/**
* Encode via <a href="http://ietf.org/rfc/rfc3986.txt">RFC 3986</a>. PCHAR is allowed allong with '/'
* <p/>
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*/
public static String encodePathSegmentAsIs(String segment)
{
return encodeFromArray(segment, pathSegmentEncoding, true);
}
/**
* Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
*
* @param segment
* @return
*/
public static String encodePathSegmentSaveEncodings(String segment)
{
String result = encodeFromArray(segment, pathSegmentEncoding, false);
result = encodeNonCodes(result);
return result;
}
/**
* Encodes everything of a query parameter name or value.
*
* @param nameOrValue
* @return
*/
public static String encodeQueryParamAsIs(String nameOrValue)
{
return encodeFromArray(nameOrValue, queryNameValueEncoding, true);
}
/**
* Keep any valid encodings from string i.e. keep "%2D" but don't keep "%p"
*
* @param segment
* @return
*/
public static String encodeQueryParamSaveEncodings(String segment)
{
String result = encodeFromArray(segment, queryNameValueEncoding, false);
result = encodeNonCodes(result);
return result;
}
public static String encodeFragmentAsIs(String nameOrValue)
{
return encodeFromArray(nameOrValue, queryNameValueEncoding, true);
}
protected static String encodeFromArray(String segment, String[] encodingMap, boolean encodePercent)
{
StringBuffer result = new StringBuffer();
for (int i = 0; i < segment.length(); i++)
{
if (!encodePercent && segment.charAt(i) == '%')
{
result.append(segment.charAt(i));
continue;
}
int idx = segment.charAt(i);
String encoding = encode(idx, encodingMap);
if (encoding == null)
{
result.append(segment.charAt(i));
}
else
{
result.append(encoding);
}
}
return result.toString();
}
/**
* @param zhar integer representation of character
* @param encodingMap encoding map
* @return URL encoded character
*/
private static String encode(int zhar, String[] encodingMap)
{
String encoded;
if (zhar < encodingMap.length)
{
encoded = encodingMap[zhar];
}
else
{
try
{
encoded = URLEncoder.encode(Character.toString((char) zhar), UTF_8);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
return encoded;
}
public static String pathParamReplacement(String segment, List<String> params)
{
StringBuffer newSegment = new StringBuffer();
Matcher matcher = PARAM_REPLACEMENT.matcher(segment);
int i = 0;
while (matcher.find())
{
String replacement = params.get(i++);
// double encode slashes, so that slashes stay where they are
replacement = replacement.replace("\\", "\\\\");
replacement = replacement.replace("$", "\\$");
matcher.appendReplacement(newSegment, replacement);
}
matcher.appendTail(newSegment);
segment = newSegment.toString();
return segment;
}
/**
* decode an encoded map
*
* @param map
* @return
*/
public static MultivaluedHashMap<String, String> decode(MultivaluedHashMap<String, String> map)
{
MultivaluedHashMap<String, String> decoded = new MultivaluedHashMap<String, String>();
for (Map.Entry<String, List<String>> entry : map.entrySet())
{
List<String> values = entry.getValue();
for (String value : values)
{
try
{
decoded.add(URLDecoder.decode(entry.getKey(), UTF_8), URLDecoder.decode(value, UTF_8));
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
}
return decoded;
}
public static MultivaluedHashMap<String, String> encode(MultivaluedHashMap<String, String> map)
{
MultivaluedHashMap<String, String> decoded = new MultivaluedHashMap<String, String>();
for (Map.Entry<String, List<String>> entry : map.entrySet())
{
List<String> values = entry.getValue();
for (String value : values)
{
try
{
decoded.add(URLEncoder.encode(entry.getKey(), UTF_8), URLEncoder.encode(value, UTF_8));
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
}
return decoded;
}
public static String decode(String string)
{
try
{
return URLDecoder.decode(string, UTF_8);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
}
@@ -1,4 +1,4 @@
package org.keycloak;
package org.keycloak.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -0,0 +1,50 @@
package org.keycloak.util;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import java.io.IOException;
import java.io.InputStream;
/**
* Utility class to handle simple JSON serializable for Keycloak.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JsonSerialization {
public static final ObjectMapper mapper = new ObjectMapper();
public static final ObjectMapper prettyMapper = new ObjectMapper();
static {
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
prettyMapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
prettyMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
prettyMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
}
public static String writeValueAsString(Object obj) throws IOException {
return mapper.writeValueAsString(obj);
}
public static byte[] writeValueAsBytes(Object obj) throws IOException {
return mapper.writeValueAsBytes(obj);
}
public static <T> T readValue(byte[] bytes, Class<T> type) throws IOException {
return mapper.readValue(bytes, type);
}
public static <T> T readValue(String bytes, Class<T> type) throws IOException {
return mapper.readValue(bytes, type);
}
public static <T> T readValue(InputStream bytes, Class<T> type) throws IOException {
return mapper.readValue(bytes, type);
}
}
@@ -0,0 +1,717 @@
package org.keycloak.util;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakUriBuilder {
private String host;
private String scheme;
private int port = -1;
private String userInfo;
private String path;
private String query;
private String fragment;
private String ssp;
private String authority;
public static KeycloakUriBuilder fromUri(URI uri) {
return new KeycloakUriBuilder().uri(uri);
}
public static KeycloakUriBuilder fromUri(String uriTemplate) {
return new KeycloakUriBuilder().uri(uriTemplate);
}
public static KeycloakUriBuilder fromPath(String path) throws IllegalArgumentException {
return new KeycloakUriBuilder().path(path);
}
public KeycloakUriBuilder clone() {
KeycloakUriBuilder impl = new KeycloakUriBuilder();
impl.host = host;
impl.scheme = scheme;
impl.port = port;
impl.userInfo = userInfo;
impl.path = path;
impl.query = query;
impl.fragment = fragment;
impl.ssp = ssp;
impl.authority = authority;
return impl;
}
public static final Pattern opaqueUri = Pattern.compile("^([^:/?#]+):([^/].*)");
public static final Pattern hierarchicalUri = Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?");
private static final Pattern hostPortPattern = Pattern.compile("([^/:]+):(\\d+)");
public static boolean compare(String s1, String s2) {
if (s1 == s2) return true;
if (s1 == null || s2 == null) return false;
return s1.equals(s2);
}
public static URI relativize(URI from, URI to) {
if (!compare(from.getScheme(), to.getScheme())) return to;
if (!compare(from.getHost(), to.getHost())) return to;
if (from.getPort() != to.getPort()) return to;
if (from.getPath() == null && to.getPath() == null) return URI.create("");
else if (from.getPath() == null) return URI.create(to.getPath());
else if (to.getPath() == null) return to;
String fromPath = from.getPath();
if (fromPath.startsWith("/")) fromPath = fromPath.substring(1);
String[] fsplit = fromPath.split("/");
String toPath = to.getPath();
if (toPath.startsWith("/")) toPath = toPath.substring(1);
String[] tsplit = toPath.split("/");
int f = 0;
for (; f < fsplit.length && f < tsplit.length; f++) {
if (!fsplit[f].equals(tsplit[f])) break;
}
KeycloakUriBuilder builder = KeycloakUriBuilder.fromPath("");
for (int i = f; i < fsplit.length; i++) builder.path("..");
for (int i = f; i < tsplit.length; i++) builder.path(tsplit[i]);
return builder.build();
}
/**
* You may put path parameters anywhere within the uriTemplate except port
*
* @param uriTemplate
* @return
*/
public static KeycloakUriBuilder fromTemplate(String uriTemplate) {
KeycloakUriBuilder impl = new KeycloakUriBuilder();
impl.uriTemplate(uriTemplate);
return impl;
}
/**
* You may put path parameters anywhere within the uriTemplate except port
*
* @param uriTemplate
* @return
*/
public KeycloakUriBuilder uriTemplate(String uriTemplate) {
if (uriTemplate == null) throw new IllegalArgumentException("uriTemplate parameter is null");
Matcher opaque = opaqueUri.matcher(uriTemplate);
if (opaque.matches()) {
this.authority = null;
this.host = null;
this.port = -1;
this.userInfo = null;
this.query = null;
this.scheme = opaque.group(1);
this.ssp = opaque.group(2);
return this;
} else {
Matcher match = hierarchicalUri.matcher(uriTemplate);
if (match.matches()) {
ssp = null;
return parseHierarchicalUri(uriTemplate, match);
}
}
throw new IllegalArgumentException("Illegal uri template: " + uriTemplate);
}
protected KeycloakUriBuilder parseHierarchicalUri(String uriTemplate, Matcher match) {
boolean scheme = match.group(2) != null;
if (scheme) this.scheme = match.group(2);
String authority = match.group(4);
if (authority != null) {
this.authority = null;
String host = match.group(4);
int at = host.indexOf('@');
if (at > -1) {
String user = host.substring(0, at);
host = host.substring(at + 1);
this.userInfo = user;
}
Matcher hostPortMatch = hostPortPattern.matcher(host);
if (hostPortMatch.matches()) {
this.host = hostPortMatch.group(1);
int val = 0;
try {
this.port = Integer.parseInt(hostPortMatch.group(2));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal uri template: " + uriTemplate, e);
}
} else {
this.host = host;
}
}
if (match.group(5) != null) {
String group = match.group(5);
if (!scheme && !"".equals(group) && !group.startsWith("/") && group.indexOf(':') > -1)
throw new IllegalArgumentException("Illegal uri template: " + uriTemplate);
if (!"".equals(group)) replacePath(group);
}
if (match.group(7) != null) replaceQuery(match.group(7));
if (match.group(9) != null) fragment(match.group(9));
return this;
}
public KeycloakUriBuilder uri(String uriTemplate) throws IllegalArgumentException {
return uriTemplate(uriTemplate);
}
public KeycloakUriBuilder uri(URI uri) throws IllegalArgumentException {
if (uri == null) throw new IllegalArgumentException("URI was null");
if (uri.getRawFragment() != null) fragment = uri.getRawFragment();
if (uri.isOpaque()) {
scheme = uri.getScheme();
ssp = uri.getRawSchemeSpecificPart();
return this;
}
if (uri.getScheme() == null) {
if (ssp != null) {
if (uri.getRawSchemeSpecificPart() != null) {
ssp = uri.getRawSchemeSpecificPart();
return this;
}
}
} else {
scheme = uri.getScheme();
}
ssp = null;
if (uri.getRawAuthority() != null) {
if (uri.getRawUserInfo() == null && uri.getHost() == null && uri.getPort() == -1) {
authority = uri.getRawAuthority();
userInfo = null;
host = null;
port = -1;
} else {
authority = null;
if (uri.getRawUserInfo() != null) {
userInfo = uri.getRawUserInfo();
}
if (uri.getHost() != null) {
host = uri.getHost();
}
if (uri.getPort() != -1) {
port = uri.getPort();
}
}
}
if (uri.getRawPath() != null && uri.getRawPath().length() > 0) {
path = uri.getRawPath();
}
if (uri.getRawQuery() != null && uri.getRawQuery().length() > 0) {
query = uri.getRawQuery();
}
return this;
}
public KeycloakUriBuilder scheme(String scheme) throws IllegalArgumentException {
this.scheme = scheme;
return this;
}
public KeycloakUriBuilder schemeSpecificPart(String ssp) throws IllegalArgumentException {
if (ssp == null) throw new IllegalArgumentException("schemeSpecificPart was null");
StringBuilder sb = new StringBuilder();
if (scheme != null) sb.append(scheme).append(':');
if (ssp != null)
sb.append(ssp);
if (fragment != null && fragment.length() > 0) sb.append('#').append(fragment);
URI uri = URI.create(sb.toString());
if (uri.getRawSchemeSpecificPart() != null && uri.getRawPath() == null) {
this.ssp = uri.getRawSchemeSpecificPart();
} else {
this.ssp = null;
userInfo = uri.getRawUserInfo();
host = uri.getHost();
port = uri.getPort();
path = uri.getRawPath();
query = uri.getRawQuery();
}
return this;
}
public KeycloakUriBuilder userInfo(String ui) {
this.userInfo = ui;
return this;
}
public KeycloakUriBuilder host(String host) throws IllegalArgumentException {
if (host != null && host.equals("")) throw new IllegalArgumentException("invalid host");
this.host = host;
return this;
}
public KeycloakUriBuilder port(int port) throws IllegalArgumentException {
if (port < -1) throw new IllegalArgumentException("Invalid port value");
this.port = port;
return this;
}
protected static String paths(boolean encode, String basePath, String... segments) {
String path = basePath;
if (path == null) path = "";
for (String segment : segments) {
if ("".equals(segment)) continue;
if (path.endsWith("/")) {
if (segment.startsWith("/")) {
segment = segment.substring(1);
if ("".equals(segment)) continue;
}
if (encode) segment = Encode.encodePath(segment);
path += segment;
} else {
if (encode) segment = Encode.encodePath(segment);
if ("".equals(path)) {
path = segment;
} else if (segment.startsWith("/")) {
path += segment;
} else {
path += "/" + segment;
}
}
}
return path;
}
public KeycloakUriBuilder path(String segment) throws IllegalArgumentException {
if (segment == null) throw new IllegalArgumentException("path was null");
path = paths(true, path, segment);
return this;
}
public KeycloakUriBuilder replaceMatrix(String matrix) throws IllegalArgumentException {
if (matrix == null) matrix = "";
if (!matrix.startsWith(";")) matrix = ";" + matrix;
matrix = Encode.encodePath(matrix);
if (path == null) {
path = matrix;
} else {
int start = path.lastIndexOf('/');
if (start < 0) start = 0;
int matrixIndex = path.indexOf(';', start);
if (matrixIndex > -1) path = path.substring(0, matrixIndex) + matrix;
else path += matrix;
}
return this;
}
public KeycloakUriBuilder replaceQuery(String query) throws IllegalArgumentException {
if (query == null || query.length() == 0) {
this.query = null;
return this;
}
this.query = Encode.encodeQueryString(query);
return this;
}
public KeycloakUriBuilder fragment(String fragment) throws IllegalArgumentException {
if (fragment == null) {
this.fragment = null;
return this;
}
this.fragment = Encode.encodeFragment(fragment);
return this;
}
/**
* Only replace path params in path of URI. This changes state of URIBuilder.
*
* @param name
* @param value
* @param isEncoded
* @return
*/
public KeycloakUriBuilder substitutePathParam(String name, Object value, boolean isEncoded) {
if (path != null) {
StringBuffer buffer = new StringBuffer();
replacePathParameter(name, value.toString(), isEncoded, path, buffer, false);
path = buffer.toString();
}
return this;
}
public URI buildFromMap(Map<String, ? extends Object> values) throws IllegalArgumentException {
if (values == null) throw new IllegalArgumentException("values parameter is null");
return buildUriFromMap(values, false, true);
}
public URI buildFromEncodedMap(Map<String, ? extends Object> values) throws IllegalArgumentException {
if (values == null) throw new IllegalArgumentException("values parameter is null");
return buildUriFromMap(values, true, false);
}
public URI buildFromMap(Map<String, ?> values, boolean encodeSlashInPath) throws IllegalArgumentException {
if (values == null) throw new IllegalArgumentException("values parameter is null");
return buildUriFromMap(values, false, encodeSlashInPath);
}
protected URI buildUriFromMap(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean encodeSlash) throws IllegalArgumentException {
String buf = buildString(paramMap, fromEncodedMap, false, encodeSlash);
try {
return URI.create(buf);
} catch (Exception e) {
throw new RuntimeException("Failed to create URI: " + buf, e);
}
}
private String buildString(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, boolean encodeSlash) {
for (Map.Entry<String, ? extends Object> entry : paramMap.entrySet()) {
if (entry.getKey() == null) throw new IllegalArgumentException("map key is null");
if (entry.getValue() == null) throw new IllegalArgumentException("map value is null");
}
StringBuffer buffer = new StringBuffer();
if (scheme != null)
replaceParameter(paramMap, fromEncodedMap, isTemplate, scheme, buffer, encodeSlash).append(":");
if (ssp != null) {
buffer.append(ssp);
} else if (userInfo != null || host != null || port != -1) {
buffer.append("//");
if (userInfo != null)
replaceParameter(paramMap, fromEncodedMap, isTemplate, userInfo, buffer, encodeSlash).append("@");
if (host != null) {
if ("".equals(host)) throw new RuntimeException("empty host name");
replaceParameter(paramMap, fromEncodedMap, isTemplate, host, buffer, encodeSlash);
}
if (port != -1) buffer.append(":").append(Integer.toString(port));
} else if (authority != null) {
buffer.append("//");
replaceParameter(paramMap, fromEncodedMap, isTemplate, authority, buffer, encodeSlash);
}
if (path != null) {
StringBuffer tmp = new StringBuffer();
replaceParameter(paramMap, fromEncodedMap, isTemplate, path, tmp, encodeSlash);
String tmpPath = tmp.toString();
if (userInfo != null || host != null) {
if (!tmpPath.startsWith("/")) buffer.append("/");
}
buffer.append(tmpPath);
}
if (query != null) {
buffer.append("?");
replaceQueryStringParameter(paramMap, fromEncodedMap, isTemplate, query, buffer);
}
if (fragment != null) {
buffer.append("#");
replaceParameter(paramMap, fromEncodedMap, isTemplate, fragment, buffer, encodeSlash);
}
return buffer.toString();
}
protected StringBuffer replacePathParameter(String name, String value, boolean isEncoded, String string, StringBuffer buffer, boolean encodeSlash) {
Matcher matcher = createUriParamMatcher(string);
while (matcher.find()) {
String param = matcher.group(1);
if (!param.equals(name)) continue;
if (!isEncoded) {
if (encodeSlash) value = Encode.encodePath(value);
else value = Encode.encodePathSegment(value);
} else {
value = Encode.encodeNonCodes(value);
}
// if there is a $ then we must backslash it or it will screw up regex group substitution
value = value.replace("$", "\\$");
matcher.appendReplacement(buffer, value);
}
matcher.appendTail(buffer);
return buffer;
}
public static Matcher createUriParamMatcher(String string) {
Matcher matcher = PathHelper.URI_PARAM_PATTERN.matcher(PathHelper.replaceEnclosedCurlyBraces(string));
return matcher;
}
protected StringBuffer replaceParameter(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, String string, StringBuffer buffer, boolean encodeSlash) {
Matcher matcher = createUriParamMatcher(string);
while (matcher.find()) {
String param = matcher.group(1);
Object valObj = paramMap.get(param);
if (valObj == null && !isTemplate) {
throw new IllegalArgumentException("NULL value for template parameter: " + param);
} else if (valObj == null && isTemplate) {
matcher.appendReplacement(buffer, matcher.group());
continue;
}
String value = valObj.toString();
if (value != null) {
if (!fromEncodedMap) {
if (encodeSlash) value = Encode.encodePathSegmentAsIs(value);
else value = Encode.encodePathAsIs(value);
} else {
if (encodeSlash) value = Encode.encodePathSegmentSaveEncodings(value);
else value = Encode.encodePathSaveEncodings(value);
}
matcher.appendReplacement(buffer, Matcher.quoteReplacement(value));
} else {
throw new IllegalArgumentException("path param " + param + " has not been provided by the parameter map");
}
}
matcher.appendTail(buffer);
return buffer;
}
protected StringBuffer replaceQueryStringParameter(Map<String, ? extends Object> paramMap, boolean fromEncodedMap, boolean isTemplate, String string, StringBuffer buffer) {
Matcher matcher = createUriParamMatcher(string);
while (matcher.find()) {
String param = matcher.group(1);
Object valObj = paramMap.get(param);
if (valObj == null && !isTemplate) {
throw new IllegalArgumentException("NULL value for template parameter: " + param);
} else if (valObj == null && isTemplate) {
matcher.appendReplacement(buffer, matcher.group());
continue;
}
String value = valObj.toString();
if (value != null) {
if (!fromEncodedMap) {
value = Encode.encodeQueryParamAsIs(value);
} else {
value = Encode.encodeQueryParamSaveEncodings(value);
}
matcher.appendReplacement(buffer, value);
} else {
throw new IllegalArgumentException("path param " + param + " has not been provided by the parameter map");
}
}
matcher.appendTail(buffer);
return buffer;
}
/**
* Return a unique order list of path params
*
* @return
*/
public List<String> getPathParamNamesInDeclarationOrder() {
List<String> params = new ArrayList<String>();
HashSet<String> set = new HashSet<String>();
if (scheme != null) addToPathParamList(params, set, scheme);
if (userInfo != null) addToPathParamList(params, set, userInfo);
if (host != null) addToPathParamList(params, set, host);
if (path != null) addToPathParamList(params, set, path);
if (query != null) addToPathParamList(params, set, query);
if (fragment != null) addToPathParamList(params, set, fragment);
return params;
}
private void addToPathParamList(List<String> params, HashSet<String> set, String string) {
Matcher matcher = PathHelper.URI_PARAM_PATTERN.matcher(PathHelper.replaceEnclosedCurlyBraces(string));
while (matcher.find()) {
String param = matcher.group(1);
if (set.contains(param)) continue;
else {
set.add(param);
params.add(param);
}
}
}
public URI build(Object... values) throws IllegalArgumentException {
if (values == null) throw new IllegalArgumentException("values parameter is null");
return buildFromValues(true, false, values);
}
protected URI buildFromValues(boolean encodeSlash, boolean encoded, Object... values) {
List<String> params = getPathParamNamesInDeclarationOrder();
if (values.length < params.size())
throw new IllegalArgumentException("You did not supply enough values to fill path parameters");
Map<String, Object> pathParams = new HashMap<String, Object>();
for (int i = 0; i < params.size(); i++) {
String pathParam = params.get(i);
Object val = values[i];
if (val == null) throw new IllegalArgumentException("A value was null");
pathParams.put(pathParam, val.toString());
}
String buf = null;
try {
buf = buildString(pathParams, encoded, false, encodeSlash);
return new URI(buf);
//return URI.create(buf);
} catch (Exception e) {
throw new RuntimeException("Failed to create URI: " + buf, e);
}
}
public KeycloakUriBuilder matrixParam(String name, Object... values) throws IllegalArgumentException {
if (name == null) throw new IllegalArgumentException("name parameter is null");
if (values == null) throw new IllegalArgumentException("values parameter is null");
if (path == null) path = "";
for (Object val : values) {
if (val == null) throw new IllegalArgumentException("null value");
path += ";" + Encode.encodeMatrixParam(name) + "=" + Encode.encodeMatrixParam(val.toString());
}
return this;
}
private static final Pattern PARAM_REPLACEMENT = Pattern.compile("_resteasy_uri_parameter");
public KeycloakUriBuilder queryParam(String name, Object... values) throws IllegalArgumentException {
if (name == null) throw new IllegalArgumentException("name parameter is null");
if (values == null) throw new IllegalArgumentException("values parameter is null");
for (Object value : values) {
if (value == null) throw new IllegalArgumentException("A passed in value was null");
if (query == null) query = "";
else query += "&";
query += Encode.encodeQueryParam(name) + "=" + Encode.encodeQueryParam(value.toString());
}
return this;
}
public KeycloakUriBuilder replaceQueryParam(String name, Object... values) throws IllegalArgumentException {
if (name == null) throw new IllegalArgumentException("name parameter is null");
if (query == null || query.equals("")) {
if (values != null) return queryParam(name, values);
return this;
}
String[] params = query.split("&");
query = null;
String replacedName = Encode.encodeQueryParam(name);
for (String param : params) {
int pos = param.indexOf('=');
if (pos >= 0) {
String paramName = param.substring(0, pos);
if (paramName.equals(replacedName)) continue;
} else {
if (param.equals(replacedName)) continue;
}
if (query == null) query = "";
else query += "&";
query += param;
}
// don't set values if values is null
if (values == null) return this;
// don't set values if values is null
if (values == null) return this;
return queryParam(name, values);
}
public String getHost() {
return host;
}
public String getScheme() {
return scheme;
}
public int getPort() {
return port;
}
public String getUserInfo() {
return userInfo;
}
public String getPath() {
return path;
}
public String getQuery() {
return query;
}
public String getFragment() {
return fragment;
}
public KeycloakUriBuilder segment(String... segments) throws IllegalArgumentException {
if (segments == null) throw new IllegalArgumentException("segments parameter was null");
for (String segment : segments) {
if (segment == null) throw new IllegalArgumentException("A segment is null");
path(Encode.encodePathSegment(segment));
}
return this;
}
public KeycloakUriBuilder replacePath(String path) {
if (path == null) {
this.path = null;
return this;
}
this.path = Encode.encodePath(path);
return this;
}
public URI build(Object[] values, boolean encodeSlashInPath) throws IllegalArgumentException {
if (values == null) throw new IllegalArgumentException("values param is null");
return buildFromValues(encodeSlashInPath, false, values);
}
public String toTemplate() {
return buildString(new HashMap<String, Object>(), true, true, true);
}
public KeycloakUriBuilder resolveTemplate(String name, Object value) throws IllegalArgumentException {
if (name == null) throw new IllegalArgumentException("name param is null");
if (value == null) throw new IllegalArgumentException("value param is null");
HashMap<String, Object> vals = new HashMap<String, Object>();
vals.put(name, value);
return resolveTemplates(vals);
}
public KeycloakUriBuilder resolveTemplates(Map<String, Object> templateValues) throws IllegalArgumentException {
if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
String str = buildString(templateValues, false, true, true);
return fromTemplate(str);
}
public KeycloakUriBuilder resolveTemplate(String name, Object value, boolean encodeSlashInPath) throws IllegalArgumentException {
if (name == null) throw new IllegalArgumentException("name param is null");
if (value == null) throw new IllegalArgumentException("value param is null");
HashMap<String, Object> vals = new HashMap<String, Object>();
vals.put(name, value);
String str = buildString(vals, false, true, encodeSlashInPath);
return fromTemplate(str);
}
public KeycloakUriBuilder resolveTemplates(Map<String, Object> templateValues, boolean encodeSlashInPath) throws IllegalArgumentException {
if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
String str = buildString(templateValues, false, true, encodeSlashInPath);
return fromTemplate(str);
}
public KeycloakUriBuilder resolveTemplatesFromEncoded(Map<String, Object> templateValues) throws IllegalArgumentException {
if (templateValues == null) throw new IllegalArgumentException("templateValues param null");
String str = buildString(templateValues, true, true, true);
return fromTemplate(str);
}
}
@@ -0,0 +1,105 @@
package org.keycloak.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@SuppressWarnings("serial")
public class MultivaluedHashMap<K, V> extends HashMap<K, List<V>>
{
public void putSingle(K key, V value)
{
List<V> list = new ArrayList<V>();
list.add(value);
put(key, list);
}
public void addAll(K key, V... newValues)
{
for (V value : newValues)
{
add(key, value);
}
}
public void addAll(K key, List<V> valueList)
{
for (V value : valueList)
{
add(key, value);
}
}
public void addFirst(K key, V value)
{
List<V> list = get(key);
if (list == null)
{
add(key, value);
return;
}
else
{
list.add(0, value);
}
}
public final void add(K key, V value)
{
getList(key).add(value);
}
public final void addMultiple(K key, Collection<V> values)
{
getList(key).addAll(values);
}
public V getFirst(K key)
{
List<V> list = get(key);
return list == null ? null : list.get(0);
}
public final List<V> getList(K key)
{
List<V> list = get(key);
if (list == null)
put(key, list = new ArrayList<V>());
return list;
}
public void addAll(MultivaluedHashMap<K, V> other)
{
for (Map.Entry<K, List<V>> entry : other.entrySet())
{
getList(entry.getKey()).addAll(entry.getValue());
}
}
public boolean equalsIgnoreValueOrder(MultivaluedHashMap<K, V> omap) {
if (this == omap) {
return true;
}
if (!keySet().equals(omap.keySet())) {
return false;
}
for (Map.Entry<K, List<V>> e : entrySet()) {
List<V> olist = omap.get(e.getKey());
if (e.getValue().size() != olist.size()) {
return false;
}
for (V v : e.getValue()) {
if (!olist.contains(v)) {
return false;
}
}
}
return true;
}
}
Loaded 100 of 484 files, more files were not shown because too many files have changed in this diff. Show more