Compare commits
162
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a20f65fc24 | ||
|
|
7d6c76cb36 | ||
|
|
0195e53768 | ||
|
|
8c4acb2ade | ||
|
|
1e75f700b8 | ||
|
|
5d5776d255 | ||
|
|
c925a76998 | ||
|
|
c77a6dfc40 | ||
|
|
ef6a0ed8e1 | ||
|
|
cbd1e0aad5 | ||
|
|
c0ab3c602c | ||
|
|
7c8eba14a0 | ||
|
|
3c91caf2b5 | ||
|
|
ebf80b6deb | ||
|
|
a5fbde222f | ||
|
|
66090e5cca | ||
|
|
e92980b776 | ||
|
|
851401c40a | ||
|
|
6865352d55 | ||
|
|
33ff1c618d | ||
|
|
564ec7ba05 | ||
|
|
ee3506ec98 | ||
|
|
c3811e2bfb | ||
|
|
fa677055cc | ||
|
|
2b38df9495 | ||
|
|
d34c73f9b9 | ||
|
|
d8df697ccf | ||
|
|
06160d6981 | ||
|
|
93210fd4f8 | ||
|
|
93f9d39ea2 | ||
|
|
d8ac7ab656 | ||
|
|
c0a1090733 | ||
|
|
070c0ddba4 | ||
|
|
c5366f1c81 | ||
|
|
cf3aa24ba5 | ||
|
|
7a6f67dfdd | ||
|
|
dcfb83b0f2 | ||
|
|
9143901ec6 | ||
|
|
41974795ce | ||
|
|
b162190c7f | ||
|
|
7294235534 | ||
|
|
894c28c64f | ||
|
|
bb38562f4f | ||
|
|
ed0d33126c | ||
|
|
f52883333a | ||
|
|
6326d5d2b5 | ||
|
|
0fe9318fa4 | ||
|
|
6b388918c9 | ||
|
|
cb391eb89a | ||
|
|
2dbd7cfa02 | ||
|
|
4825974edc | ||
|
|
62cc002396 | ||
|
|
8037b02ad8 | ||
|
|
39b61728d6 | ||
|
|
355d4bdf91 | ||
|
|
99016c185f | ||
|
|
b59e60ff38 | ||
|
|
c751d8b60f | ||
|
|
ba0d780380 | ||
|
|
d309fab825 | ||
|
|
e904ca8b58 | ||
|
|
2e40e63c4c | ||
|
|
d6512f0333 | ||
|
|
4b6ebc339f | ||
|
|
5df362a523 | ||
|
|
b684357022 | ||
|
|
354abf8a4a | ||
|
|
f2c0eed8f2 | ||
|
|
8ef194a205 | ||
|
|
6146dd48f7 | ||
|
|
739866de0c | ||
|
|
90f125b03a | ||
|
|
50082de51d | ||
|
|
8b66234ab9 | ||
|
|
86b9fb688c | ||
|
|
4dd9170a99 | ||
|
|
626839f0f3 | ||
|
|
6647ddb66e | ||
|
|
0a57ba026b | ||
|
|
f14931d234 | ||
|
|
fcac30d3a2 | ||
|
|
aaae0ff2f7 | ||
|
|
f63872b8b0 | ||
|
|
ddbb63f3d1 | ||
|
|
7daa6f492e | ||
|
|
60f30446ba | ||
|
|
734bc5c902 | ||
|
|
d8ef13c133 | ||
|
|
a1b7297f25 | ||
|
|
e393a347cc | ||
|
|
30cb9df307 | ||
|
|
834baf0e27 | ||
|
|
f78a306ba0 | ||
|
|
69b25407b1 | ||
|
|
e17c7c2c1b | ||
|
|
40e8a26a3b | ||
|
|
0ec80f6590 | ||
|
|
16f5bbc54e | ||
|
|
212aec8ae3 | ||
|
|
dd84679e3f | ||
|
|
c755c7562c | ||
|
|
cbf46720c7 | ||
|
|
bbd3ac22d1 | ||
|
|
d1693c9c7e | ||
|
|
36bdd43488 | ||
|
|
1f63e87cd6 | ||
|
|
addefbb587 | ||
|
|
1f8081629e | ||
|
|
6380dc3d1b | ||
|
|
6fe9a03997 | ||
|
|
ac64eba667 | ||
|
|
d22b6f8df7 | ||
|
|
4e03ca51af | ||
|
|
d28b1ff98b | ||
|
|
698b5a1a16 | ||
|
|
07e003325b | ||
|
|
c7b096cf7d | ||
|
|
a144ab07f2 | ||
|
|
fbe8c5cdec | ||
|
|
00a7d88dee | ||
|
|
a4842fe6bc | ||
|
|
6d9e1ea60c | ||
|
|
11524e28db | ||
|
|
ad249112bf | ||
|
|
ab636f4af5 | ||
|
|
ad3c964be7 | ||
|
|
42c7687309 | ||
|
|
8e3e99f392 | ||
|
|
bec267237a | ||
|
|
a2e312b3f1 | ||
|
|
94a70e78ca | ||
|
|
7076341f7f | ||
|
|
e052b6f99f | ||
|
|
809c4b3673 | ||
|
|
331f321274 | ||
|
|
07f9fd3de3 | ||
|
|
53e61326c1 | ||
|
|
faec1e5340 | ||
|
|
6e13dc8db7 | ||
|
|
145eab98d8 | ||
|
|
cd8c8d52e8 | ||
|
|
0dad786b35 | ||
|
|
43da684a91 | ||
|
|
c368a64b4b | ||
|
|
8011622e25 | ||
|
|
72a330fe85 | ||
|
|
c63abbdf3e | ||
|
|
edba13e596 | ||
|
|
805863dde6 | ||
|
|
c514e6c152 | ||
|
|
a423c38e42 | ||
|
|
36a20d15e1 | ||
|
|
468a060f55 | ||
|
|
d0f4ac47ea | ||
|
|
e646f0afe5 | ||
|
|
e4376604c5 | ||
|
|
96c807d761 | ||
|
|
3ffab32eb3 | ||
|
|
0fdab8c9f1 | ||
|
|
832c6ebaf1 | ||
|
|
b76f625eaf | ||
|
|
d86dec6561 |
No files matched your search
Executable
+210
@@ -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>
|
||||
@@ -1,4 +1,4 @@
|
||||
keycloak
|
||||
========
|
||||
|
||||
SSO SaaS
|
||||
SSO Service for web apps and REST services.
|
||||
@@ -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>
|
||||
|
||||
+11
-85
@@ -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
-84
@@ -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
@@ -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) {
|
||||
|
||||
+37
-33
@@ -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++) {
|
||||
|
||||
+23
-15
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
+72
@@ -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||{}});
|
||||
+25
@@ -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);
|
||||
}
|
||||
}
|
||||
+2
@@ -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));
|
||||
Vendored
+215
@@ -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);
|
||||
}
|
||||
})();
|
||||
}})();
|
||||
Vendored
+2
@@ -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)}}()}}();
|
||||
+156
@@ -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);
|
||||
}
|
||||
};
|
||||
} ]);
|
||||
|
||||
})();
|
||||
Vendored
+2
@@ -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)}}}])}();
|
||||
+9
-9
@@ -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>
|
||||
|
||||
+11
-11
@@ -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>
|
||||
|
||||
+6
-6
@@ -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>
|
||||
|
||||
+14
-14
@@ -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>
|
||||
|
||||
|
||||
+12
-12
@@ -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>
|
||||
|
||||
+8
-8
@@ -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>
|
||||
|
||||
+27
@@ -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>
|
||||
+7
-6
@@ -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>
|
||||
|
||||
+9
-8
@@ -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>
|
||||
|
||||
Executable
+25
@@ -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>
|
||||
+5
-5
@@ -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>
|
||||
|
||||
+7
-6
@@ -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>
|
||||
|
||||
-32
@@ -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>
|
||||
-36
@@ -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>
|
||||
-40
@@ -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>
|
||||
+55
@@ -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>
|
||||
+128
-128
@@ -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>
|
||||
+11
-11
@@ -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>
|
||||
|
||||
Executable
+71
@@ -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>
|
||||
File renamed without changes.
+7
-12
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
+10
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
+3
-14
@@ -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;
|
||||
}
|
||||
+2
-3
@@ -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;
|
||||
}
|
||||
|
||||
+104
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+123
@@ -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;
|
||||
}
|
||||
}
|
||||
+54
@@ -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;
|
||||
}
|
||||
}
|
||||
-80
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+2091
File diff suppressed because it is too large.
Load diff
+42
@@ -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
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak;
|
||||
package org.keycloak.util;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak;
|
||||
package org.keycloak.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
+526
@@ -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
-1
@@ -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
Reference in new issue
Block a user