Compare commits
182
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f429e4150 | ||
|
|
9528dbc4dc | ||
|
|
3ff8d0fd1f | ||
|
|
7b64d9975e | ||
|
|
ba60a0c04b | ||
|
|
6926f02cc3 | ||
|
|
52018b1f81 | ||
|
|
fcc95ef99b | ||
|
|
2f29fab931 | ||
|
|
0c2767afd7 | ||
|
|
4a90133d29 | ||
|
|
3c40e9694f | ||
|
|
30358a7582 | ||
|
|
20880ffd71 | ||
|
|
e48cc006f6 | ||
|
|
accb56be7f | ||
|
|
a1ea79e382 | ||
|
|
a1f10ef54b | ||
|
|
fbc39e82a1 | ||
|
|
0214827492 | ||
|
|
6dc156712e | ||
|
|
53f671e8af | ||
|
|
a15e7d1f6e | ||
|
|
e836371887 | ||
|
|
53b596d435 | ||
|
|
0dbd4417af | ||
|
|
d1b1a98a0a | ||
|
|
ccc4f5a114 | ||
|
|
03a0cce119 | ||
|
|
26b3ec0b2a | ||
|
|
7992509fde | ||
|
|
b208cae333 | ||
|
|
9749c65065 | ||
|
|
9109642821 | ||
|
|
b6503748ca | ||
|
|
0284d040dc | ||
|
|
d8c13c9ac2 | ||
|
|
be7008f253 | ||
|
|
63bc2d6dbb | ||
|
|
3d0d130622 | ||
|
|
8c3225914c | ||
|
|
798e3ce86b | ||
|
|
49c79f156a | ||
|
|
d3634c1180 | ||
|
|
c345ee9e5a | ||
|
|
12f080e803 | ||
|
|
2b01de5ecf | ||
|
|
61102845ed | ||
|
|
ca3b28fda7 | ||
|
|
854158a9c2 | ||
|
|
11bcd84738 | ||
|
|
da3f1a21a2 | ||
|
|
2edb93ef54 | ||
|
|
0f0353674d | ||
|
|
62b0789e5f | ||
|
|
26d0f993ba | ||
|
|
a653e5a406 | ||
|
|
0fd0240be7 | ||
|
|
3ea9df89a9 | ||
|
|
3c463419ca | ||
|
|
dd292c1d52 | ||
|
|
801ef3281a | ||
|
|
8f29bf0a5a | ||
|
|
6f752e68c8 | ||
|
|
12978a4343 | ||
|
|
b543e22eee | ||
|
|
599faa3cb5 | ||
|
|
d7b616773a | ||
|
|
633ddb70e7 | ||
|
|
d0a6a8ae3b | ||
|
|
60bb05e6ca | ||
|
|
0219aa1e4c | ||
|
|
34260b7428 | ||
|
|
d6bd02ea7d | ||
|
|
7699dd2701 | ||
|
|
2d86b29b6c | ||
|
|
67db515fe1 | ||
|
|
df61879fb1 | ||
|
|
77259320cf | ||
|
|
e0dff8104d | ||
|
|
9816fdd842 | ||
|
|
9d4cc19e62 | ||
|
|
06288fa07b | ||
|
|
735486c36e | ||
|
|
d783c6200e | ||
|
|
e307916233 | ||
|
|
01154f18dd | ||
|
|
716972347d | ||
|
|
4b8c6f338a | ||
|
|
170afedd19 | ||
|
|
8881ba2d72 | ||
|
|
1cff76922b | ||
|
|
c0f49763f1 | ||
|
|
87aaaf0b06 | ||
|
|
ec309e7e02 | ||
|
|
22b25a0d9e | ||
|
|
8126110312 | ||
|
|
f8eb56d6b7 | ||
|
|
21b1ad5e0a | ||
|
|
5eddacfee9 | ||
|
|
c8023c6651 | ||
|
|
7b30cc59b8 | ||
|
|
581d64614e | ||
|
|
0d309d058c | ||
|
|
11559cba50 | ||
|
|
e02d3748a9 | ||
|
|
236d67f78d | ||
|
|
4dc4c56921 | ||
|
|
cec3df71ca | ||
|
|
63aa303673 | ||
|
|
3e68cc601a | ||
|
|
918e3d17f6 | ||
|
|
c78d1c90e4 | ||
|
|
3fc273070e | ||
|
|
7aa7df43aa | ||
|
|
d65926f3b8 | ||
|
|
5881ef3e11 | ||
|
|
f8da693fd0 | ||
|
|
b413636bf5 | ||
|
|
a1dca73ad3 | ||
|
|
32b7c464c7 | ||
|
|
d5e0e73369 | ||
|
|
b3375d4279 | ||
|
|
4f56170b4c | ||
|
|
42d30a5a70 | ||
|
|
9dbd19f715 | ||
|
|
48d39bf977 | ||
|
|
a8e588216b | ||
|
|
c02d532001 | ||
|
|
0f67feb9dd | ||
|
|
b2719ff40a | ||
|
|
8613452f4f | ||
|
|
b249809d2e | ||
|
|
4ea7808d5f | ||
|
|
ae1b98e38f | ||
|
|
d0ca9a655d | ||
|
|
8d5d786452 | ||
|
|
deaf2f9273 | ||
|
|
db37053f58 | ||
|
|
dd75864749 | ||
|
|
98629ac6f8 | ||
|
|
fa39ec1c98 | ||
|
|
9a73936002 | ||
|
|
7f33593931 | ||
|
|
88fb1ec747 | ||
|
|
a3e437f82a | ||
|
|
64065a4573 | ||
|
|
1acfe1502a | ||
|
|
4b78857b51 | ||
|
|
735009cdd7 | ||
|
|
166e00f2e8 | ||
|
|
3552f9e4aa | ||
|
|
01ddafa83a | ||
|
|
1bfad2e198 | ||
|
|
3e88cb3b76 | ||
|
|
273e706a42 | ||
|
|
baa0e453b6 | ||
|
|
898fcf8fd5 | ||
|
|
3b59bd92fc | ||
|
|
0a9b82a6f4 | ||
|
|
8a4ef40e9e | ||
|
|
e85c2c9826 | ||
|
|
15968e9783 | ||
|
|
97dd7470ce | ||
|
|
e583dc60ae | ||
|
|
9607acdb6a | ||
|
|
0ee71b09cd | ||
|
|
05bd92d765 | ||
|
|
cd68462cf3 | ||
|
|
9442601e42 | ||
|
|
4b1fc788cf | ||
|
|
94d8dbeeee | ||
|
|
3cb7e7c1bf | ||
|
|
9ce8e16063 | ||
|
|
c2ca1b2731 | ||
|
|
d47bf103b0 | ||
|
|
dfacae9beb | ||
|
|
6794166b58 | ||
|
|
8583d35153 | ||
|
|
2cb37827a8 | ||
|
|
158eec7999 | ||
|
|
00043423c2 |
No files matched your search
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-alpha-2</version>
|
||||
<version>1.0-alpha-3</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+89
-43
@@ -2,10 +2,17 @@ body {
|
||||
background-color: #F9F9F9;
|
||||
}
|
||||
|
||||
.header .container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-title {
|
||||
background-image: url('../img/logo.png');
|
||||
height: 25px;
|
||||
background-repeat: no-repeat;
|
||||
width: 103px;
|
||||
margin: 3px 10px 5px;
|
||||
text-indent: -99999px;
|
||||
}
|
||||
|
||||
.navbar-pf {
|
||||
@@ -29,13 +36,24 @@ body {
|
||||
.navbar-pf .navbar-primary > .active > a,
|
||||
.navbar-pf .navbar-primary > .active > a:hover{
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
border-bottom-color: rgba(0,0,0,0.3);
|
||||
border-right: rgba(0,0,0,0.3);
|
||||
border-top-color: rgba(0,0,0,0.1);
|
||||
font-weight: 600;
|
||||
background-image: -webkit-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.1) 100%);
|
||||
background-image: linear-gradient(to bottom, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.1) 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-bottom: none;
|
||||
border-right-color: rgba(255,255,255,0.15);
|
||||
border-top-color: rgba(255,255,255,0.05);
|
||||
}
|
||||
|
||||
.navbar-nav > li > .dropdown-menu {
|
||||
left: 15px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-primary li.dropdown.context > a {
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-primary > li > a {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-primary li.dropdown.context > a:hover,
|
||||
@@ -55,8 +73,20 @@ body {
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility > li > a {
|
||||
.navbar-pf .navbar-utility {
|
||||
right: 15px;
|
||||
top: -34px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility li.dropdown > .dropdown-toggle {
|
||||
border-left: none;
|
||||
padding-top: 11px;
|
||||
padding-bottom: 12px;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility li.dropdown > .dropdown-toggle .pficon-user {
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-utility > li > a:hover,
|
||||
@@ -65,12 +95,12 @@ body {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
#content, #content-area {
|
||||
background-color: #FFFFFF;
|
||||
html, body, body > .container, #view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html, body, body > .container, #view, #content-area{
|
||||
height: 100%;
|
||||
body > .container {
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
|
||||
#content .glyphicon {
|
||||
@@ -107,7 +137,7 @@ html, body, body > .container, #view, #content-area{
|
||||
|
||||
.fieldset-notice {
|
||||
color: #B7B7B7;
|
||||
font-size: 1.1em;
|
||||
font-size: 11px;
|
||||
float: right;
|
||||
margin-top: -2em;
|
||||
}
|
||||
@@ -128,7 +158,9 @@ th.kc-table-actions {
|
||||
border-color: #CECECE;
|
||||
border-style: solid;
|
||||
border-width: 0 1px;
|
||||
padding: 0;
|
||||
padding: 0 0 40px;
|
||||
background-color: #fff;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
#content-area > * {
|
||||
@@ -137,10 +169,9 @@ th.kc-table-actions {
|
||||
|
||||
#content-area > .nav {
|
||||
border-color: #CECECE;
|
||||
font-size: 1.4em;
|
||||
padding: 0 20px;
|
||||
margin-bottom: 0;
|
||||
padding: 0.8em 0 0 2em;
|
||||
padding: 10px 0 0 30px;
|
||||
}
|
||||
|
||||
#container-right-bg {
|
||||
@@ -159,15 +190,6 @@ header .navbar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.navbar-pf .navbar-title {
|
||||
color: #ddd;
|
||||
margin: .3em .4em;
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
font-size: 1.3em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#idletimeout {
|
||||
background: #CC5100;
|
||||
color: #FFFFFF;
|
||||
@@ -193,6 +215,7 @@ header .navbar {
|
||||
color: #0099D3;
|
||||
letter-spacing: 0;
|
||||
padding: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
.kc-link:hover {
|
||||
text-decoration: underline;
|
||||
@@ -241,6 +264,10 @@ header .navbar {
|
||||
font-size: 0.90909090909091em;
|
||||
}
|
||||
|
||||
form .btn + .btn {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
/* Top menu */
|
||||
|
||||
#kc-navigation li.active {
|
||||
@@ -251,7 +278,7 @@ header .navbar {
|
||||
|
||||
.bs-sidebar {
|
||||
background-color: #f9f9f9;
|
||||
padding-top: 4.3em;
|
||||
padding-top: 43px;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
z-index: 20;
|
||||
@@ -266,11 +293,10 @@ header .navbar {
|
||||
margin-left: -1em;
|
||||
}
|
||||
.bs-sidebar ul li a {
|
||||
font-size: 1.3em;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
padding-left: 1.92307692307692em;
|
||||
font-size: 13px;
|
||||
padding-left: 25px;
|
||||
color: #4d5258;
|
||||
line-height: 2.07692307692308em;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
border-width: 1px 0 1px 1px;
|
||||
border-style: solid;
|
||||
@@ -280,6 +306,7 @@ header .navbar {
|
||||
.bs-sidebar ul li a:focus {
|
||||
text-decoration: none;
|
||||
color: #777777;
|
||||
border-right: 2px solid #aaa;
|
||||
}
|
||||
.bs-sidebar ul li.active a {
|
||||
background-color: #c7e5f0;
|
||||
@@ -290,6 +317,10 @@ header .navbar {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.bs-sidebar ul li.active a:hover {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* On-Off switch */
|
||||
|
||||
.onoffswitch {
|
||||
@@ -355,8 +386,8 @@ header .navbar {
|
||||
color: #FFFFFF;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.onoffswitch.disabled .onoffswitch-inner .onoffswitch-active,
|
||||
.onoffswitch.disabled .onoffswitch-inner .onoffswitch-inactive {
|
||||
.onoffswitch-checkbox:disabled + .onoffswitch-label .onoffswitch-inner .onoffswitch-active,
|
||||
.onoffswitch-checkbox:disabled + .onoffswitch-label .onoffswitch-inner .onoffswitch-inactive {
|
||||
background-image: none;
|
||||
background-color: #e5e5e5;
|
||||
color: #9d9fa1;
|
||||
@@ -377,8 +408,9 @@ header .navbar {
|
||||
/* Inputs */
|
||||
|
||||
.form-horizontal .control-label {
|
||||
text-align: left;
|
||||
color: #909090;
|
||||
line-height: 1.4em;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
/* Details stuff */
|
||||
@@ -386,9 +418,13 @@ header .navbar {
|
||||
#content h2 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 100;
|
||||
font-size: 2.4em;
|
||||
margin-bottom: 1.04166666666667em;
|
||||
margin-top: 1em;
|
||||
font-size: 24px;
|
||||
margin-bottom: 25px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#content h2.margin-top {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
#content-area #content h2 span {
|
||||
@@ -399,6 +435,14 @@ fieldset {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
fieldset.border-top {
|
||||
border-top: 1px solid #E9E8E8;
|
||||
}
|
||||
|
||||
fieldset.border-top .form-group:first-child {
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
/* Legend stuff */
|
||||
legend {
|
||||
border-color: #E9E8E8;
|
||||
@@ -406,14 +450,14 @@ legend {
|
||||
border-width: 1px 0 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font-size: 1em;
|
||||
font-size: 13px;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 1em;
|
||||
padding-top: 2em;
|
||||
padding-bottom: 13px;
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
legend .text {
|
||||
font-size: 1.3em;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #505050;
|
||||
}
|
||||
@@ -550,7 +594,7 @@ legend .kc-icon-collapse {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: medium none;
|
||||
font-family: "Open Sans",sans-serif;
|
||||
font-size: 1.1em;
|
||||
font-size: 11px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-left: -2px;
|
||||
@@ -591,7 +635,7 @@ legend .kc-icon-collapse {
|
||||
display: inline-block;
|
||||
}
|
||||
.changing-selectors .select-title label {
|
||||
font-size: 1.1em;
|
||||
font-size: 11px;
|
||||
margin-left: 0.2em;
|
||||
margin-bottom: 0.3em;
|
||||
margin-top: 0.5em;
|
||||
@@ -600,7 +644,7 @@ legend .kc-icon-collapse {
|
||||
}
|
||||
.changing-selectors select {
|
||||
min-height: 150px;
|
||||
font-size: 1.1em;
|
||||
font-size: 11px;
|
||||
padding: 0.545454545454545em;
|
||||
min-width: 18.1818181818182em;
|
||||
border: 1px #b6b6b6 solid;
|
||||
@@ -665,9 +709,11 @@ legend .kc-icon-collapse {
|
||||
.kc-uploaded-file {
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
margin-right: 0.909091em;
|
||||
padding-top: 3px;
|
||||
margin-right: 10px;
|
||||
padding-top: 5px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.kc-link-input-file {
|
||||
display: inline-block;
|
||||
margin-top: 0.1em;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.5 KiB |
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-alpha-2</version>
|
||||
<version>1.0-alpha-3</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<script src="lib/angular/angular.js"></script>
|
||||
<script src="lib/angular/angular-resource.js"></script>
|
||||
<script src="lib/angular/angular-route.js"></script>
|
||||
<script src="lib/angular/ui-bootstrap-tpls-0.4.0.js"></script>
|
||||
|
||||
<script src="lib/jquery/jquery.idletimer.js" type="text/javascript"></script>
|
||||
@@ -66,9 +67,7 @@
|
||||
</div>
|
||||
|
||||
<header class="navbar navbar-default navbar-pf navbar-main header">
|
||||
<div class="container">
|
||||
<div data-ng-include data-src="'partials/menu.html'"></div>
|
||||
</div>
|
||||
<div data-ng-include data-src="'partials/menu.html'"></div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
@@ -67,92 +67,93 @@
|
||||
</div>
|
||||
|
||||
<header class="navbar navbar-default navbar-pf navbar-main header">
|
||||
<div class="container">
|
||||
<nav id="kc-navigation" class="navbar" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<h1 class="navbar-title"><Strong>KeyCloak</Strong> Central Login</h1>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.loggedIn">
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="pficon pficon-user"></span>
|
||||
{{auth.user.displayName}}<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/auth/rest/realms/keycloak-admin/account?referrer=admin-console">Manage Account</a></li>
|
||||
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-primary persistent-secondary" data-ng-controller="RealmDropdownCtrl">
|
||||
<li class="dropdown context" data-ng-show="showNav()">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
Realm: {{current.realm.id}}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-ng-repeat="realm in current.realms">
|
||||
<a href="" ng-click="changeRealm(realm.id)" >{{realm.id}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<!--------------------------------------->
|
||||
<li class="active">
|
||||
<a href="#">Settings</a>
|
||||
<ul class="nav navbar-nav navbar-persistent">
|
||||
<li class="active">
|
||||
<a href="#">General</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Roles</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Default Roles</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Credentials</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Token</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Keys</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Email</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">User</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Applications</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">OAuth Clients</a>
|
||||
</li>
|
||||
<!--------------------------------------->
|
||||
|
||||
|
||||
<li class="active pull-right" data-ng-show="auth.loggedIn">
|
||||
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
<nav id="kc-navigation" class="navbar" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<div class="container">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<h1 class="navbar-title"><Strong>KeyCloak</Strong> Central Login</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-collapse-1">
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.loggedIn">
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="pficon pficon-user"></span>
|
||||
{{auth.user.displayName}}<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/auth/rest/realms/keycloak-admin/account?referrer=admin-console">Manage Account</a></li>
|
||||
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-primary persistent-secondary" data-ng-controller="RealmDropdownCtrl">
|
||||
<li class="dropdown context" data-ng-show="showNav()">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
Realm: {{current.realm.id}}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-ng-repeat="realm in current.realms">
|
||||
<a href="" ng-click="changeRealm(realm.id)" >{{realm.id}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
||||
<!--------------------------------------->
|
||||
<li class="active">
|
||||
<a href="#">Settings</a>
|
||||
<ul class="nav navbar-nav navbar-persistent">
|
||||
<li class="active">
|
||||
<a href="#">General</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Roles</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Default Roles</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Credentials</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Token</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Keys</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Email</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">User</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Applications</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">OAuth Clients</a>
|
||||
</li>
|
||||
<!--------------------------------------->
|
||||
|
||||
|
||||
<li class="active pull-right" data-ng-show="auth.loggedIn">
|
||||
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
|
||||
@@ -35,6 +35,7 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
controller : 'RealmDetailCtrl'
|
||||
})
|
||||
*/
|
||||
|
||||
.when('/create/realm', {
|
||||
templateUrl : 'partials/realm-create.html',
|
||||
resolve : {
|
||||
@@ -175,6 +176,21 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
},
|
||||
controller : 'UserRoleMappingCtrl'
|
||||
})
|
||||
.when('/realms/:realm/users/:user/sessions', {
|
||||
templateUrl : 'partials/user-sessions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
user : function(UserLoader) {
|
||||
return UserLoader();
|
||||
},
|
||||
stats : function(UserSessionStatsLoader) {
|
||||
return UserSessionStatsLoader();
|
||||
}
|
||||
},
|
||||
controller : 'UserSessionsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/users', {
|
||||
templateUrl : 'partials/user-list.html',
|
||||
resolve : {
|
||||
@@ -276,6 +292,36 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
},
|
||||
controller : 'ApplicationRoleDetailCtrl'
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/claims', {
|
||||
templateUrl : 'partials/application-claims.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
application : function(ApplicationLoader) {
|
||||
return ApplicationLoader();
|
||||
},
|
||||
claims : function(ApplicationClaimsLoader) {
|
||||
return ApplicationClaimsLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ApplicationClaimsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/sessions', {
|
||||
templateUrl : 'partials/application-sessions.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
application : function(ApplicationLoader) {
|
||||
return ApplicationLoader();
|
||||
},
|
||||
stats : function(ApplicationSessionStatsLoader) {
|
||||
return ApplicationSessionStatsLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ApplicationSessionsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/credentials', {
|
||||
templateUrl : 'partials/application-credentials.html',
|
||||
resolve : {
|
||||
@@ -303,6 +349,18 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
},
|
||||
controller : 'ApplicationRoleListCtrl'
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/revocation', {
|
||||
templateUrl : 'partials/application-revocation.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
application : function(ApplicationLoader) {
|
||||
return ApplicationLoader();
|
||||
}
|
||||
},
|
||||
controller : 'ApplicationRevocationCtrl'
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/scope-mappings', {
|
||||
templateUrl : 'partials/application-scope-mappings.html',
|
||||
resolve : {
|
||||
@@ -333,18 +391,6 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
},
|
||||
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 : {
|
||||
@@ -390,6 +436,33 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
|
||||
// OAUTH Client
|
||||
|
||||
.when('/realms/:realm/oauth-clients/:oauth/claims', {
|
||||
templateUrl : 'partials/oauth-client-claims.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
oauth : function(OAuthClientLoader) {
|
||||
return OAuthClientLoader();
|
||||
},
|
||||
claims : function(OAuthClientClaimsLoader) {
|
||||
return OAuthClientClaimsLoader();
|
||||
}
|
||||
},
|
||||
controller : 'OAuthClientClaimsCtrl'
|
||||
})
|
||||
.when('/realms/:realm/oauth-clients/:oauth/revocation', {
|
||||
templateUrl : 'partials/oauth-client-revocation.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
oauth : function(OAuthClientLoader) {
|
||||
return OAuthClientLoader();
|
||||
}
|
||||
},
|
||||
controller : 'OAuthClientRevocationCtrl'
|
||||
})
|
||||
.when('/realms/:realm/oauth-clients/:oauth/credentials', {
|
||||
templateUrl : 'partials/oauth-client-credentials.html',
|
||||
resolve : {
|
||||
@@ -488,6 +561,28 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||
},
|
||||
controller : 'RealmDetailCtrl'
|
||||
})
|
||||
.when('/realms/:realm/sessions/revocation', {
|
||||
templateUrl : 'partials/session-revocation.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmRevocationCtrl'
|
||||
})
|
||||
.when('/realms/:realm/sessions/realm', {
|
||||
templateUrl : 'partials/session-realm.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
stats : function(RealmSessionStatsLoader) {
|
||||
return RealmSessionStatsLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmSessionStatsCtrl'
|
||||
})
|
||||
|
||||
.otherwise({
|
||||
templateUrl : 'partials/notfound.html'
|
||||
});
|
||||
@@ -521,6 +616,8 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location,
|
||||
console.log('session timeout?');
|
||||
Auth.loggedIn = false;
|
||||
window.location = '/auth/rest/admin/login?path=' + $location.path();
|
||||
} else if (response.status == 403) {
|
||||
Notifications.error("Forbidden");
|
||||
} else if (response.status == 404) {
|
||||
Notifications.error("Not found");
|
||||
} else if (response.status) {
|
||||
@@ -608,35 +705,37 @@ module.directive('collapsed', function() {
|
||||
module.directive('onoffswitch', function() {
|
||||
return {
|
||||
restrict: "EA",
|
||||
require: 'ngModel',
|
||||
replace: true,
|
||||
scope: {
|
||||
name: '@',
|
||||
id: '@',
|
||||
ngModel: '=',
|
||||
ngDisabled: '=',
|
||||
ngBind: '=',
|
||||
name: '=',
|
||||
id: '=',
|
||||
onText: '@onText',
|
||||
offText: '@offText'
|
||||
kcOnText: '@onText',
|
||||
kcOffText: '@offText'
|
||||
},
|
||||
// TODO - The same code acts differently when put into the templateURL. Find why and move the code there.
|
||||
//templateUrl: "templates/kc-switch.html",
|
||||
template: "<span><div class='onoffswitch' tabindex='0'><input type='checkbox' ng-model='ngModel' ng-disabled='ngDisabled' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'><label for='{{id}}' class='onoffswitch-label'><span class='onoffswitch-inner'><span class='onoffswitch-active'>{{kcOnText}}</span><span class='onoffswitch-inactive'>{{kcOffText}}</span></span><span class='onoffswitch-switch'></span></label></div></span>",
|
||||
compile: function(element, attrs) {
|
||||
/*
|
||||
We don't want to propagate basic attributes to the root element of directive. Id should be passed to the
|
||||
input element only to achieve proper label binding (and validity).
|
||||
*/
|
||||
element.removeAttr('name');
|
||||
element.removeAttr('id');
|
||||
|
||||
if (!attrs.onText) { attrs.onText = "ON"; }
|
||||
if (!attrs.offText) { attrs.offText = "OFF"; }
|
||||
if (!attrs.ngDisabled) { attrs.ngDisabled = false; }
|
||||
|
||||
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\">" +
|
||||
"<span class=\"onoffswitch-inner\">" +
|
||||
"<span class=\"onoffswitch-active\">{{onText}}</span>" +
|
||||
"<span class=\"onoffswitch-inactive\">{{offText}}</span>" +
|
||||
"</span>" +
|
||||
"<span class=\"onoffswitch-switch\"></span>" +
|
||||
"</label>" +
|
||||
"</div></span>";
|
||||
|
||||
element.replaceWith($(html));
|
||||
element.bind('keydown', function(e){
|
||||
var code = e.keyCode || e.which;
|
||||
if (code === 32 || code === 13) {
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
$(e.target).find('input').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -758,7 +857,7 @@ module.directive('kcDelete', function ($compile, Notifications) {
|
||||
});
|
||||
|
||||
|
||||
module.directive('kcSelect', function ($compile, Notifications) {
|
||||
module.directive('kcDropdown', function ($compile, Notifications) {
|
||||
return {
|
||||
scope: {
|
||||
kcOptions: '=',
|
||||
@@ -777,13 +876,49 @@ module.directive('kcSelect', function ($compile, Notifications) {
|
||||
}
|
||||
});
|
||||
|
||||
module.directive('kcReadOnly', function() {
|
||||
var disabled = {};
|
||||
|
||||
var d = {
|
||||
replace : false,
|
||||
link : function(scope, element, attrs) {
|
||||
var disable = function(i, e) {
|
||||
if (!e.disabled) {
|
||||
disabled[e.tagName + i] = true;
|
||||
e.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var enable = function(i, e) {
|
||||
if (disabled[e.tagName + i]) {
|
||||
e.disabled = false;
|
||||
delete disabled[i];
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch(attrs.kcReadOnly, function(readOnly) {
|
||||
if (readOnly) {
|
||||
console.debug('readonly');
|
||||
element.find('input').each(disable);
|
||||
element.find('button').each(disable);
|
||||
element.find('select').each(disable);
|
||||
element.find('textarea').each(disable);
|
||||
} else {
|
||||
element.find('input').each(enable);
|
||||
element.find('input').each(enable);
|
||||
element.find('button').each(enable);
|
||||
element.find('select').each(enable);
|
||||
element.find('textarea').each(enable);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return d;
|
||||
});
|
||||
|
||||
module.directive('kcNavigation', function ($compile, Notifications) {
|
||||
return {
|
||||
scope: {
|
||||
kcCurrent: '@',
|
||||
kcRealm: '=',
|
||||
kcSocial: '='
|
||||
},
|
||||
scope: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'templates/kc-navigation.html',
|
||||
|
||||
+148
-2
@@ -3,6 +3,10 @@ module.controller('ApplicationRoleListCtrl', function($scope, $location, realm,
|
||||
$scope.roles = roles;
|
||||
$scope.application = application;
|
||||
|
||||
for (var i = 0; i < roles.length; i++) {
|
||||
console.log("role.id: " + roles[i].id + " role.name: " + roles[i].name);
|
||||
}
|
||||
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function() {
|
||||
@@ -39,11 +43,80 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
|
||||
});
|
||||
});
|
||||
|
||||
module.controller('ApplicationSessionsCtrl', function($scope, $location, realm, application) {
|
||||
module.controller('ApplicationSessionsCtrl', function($scope, realm, stats, application,
|
||||
ApplicationLogoutUser,
|
||||
ApplicationLogoutAll,
|
||||
ApplicationSessionStats,
|
||||
ApplicationSessionStatsWithUsers,
|
||||
$location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.stats = stats;
|
||||
$scope.users = {};
|
||||
$scope.application = application;
|
||||
|
||||
$scope.toDate = function(val) {
|
||||
return new Date(val);
|
||||
};
|
||||
|
||||
$scope.loadUsers = function() {
|
||||
ApplicationSessionStatsWithUsers.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
|
||||
$scope.stats = updated;
|
||||
$scope.users = updated.users;
|
||||
})
|
||||
};
|
||||
|
||||
$scope.logoutAll = function() {
|
||||
ApplicationLogoutAll.save({realm : realm.realm, application: $scope.application.name}, function () {
|
||||
Notifications.success('Logged out all users');
|
||||
$scope.loadUsers();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.logoutUser = function(user) {
|
||||
console.log('Trying to logout user: ' + user);
|
||||
ApplicationLogoutUser.save({realm : realm.realm, application: $scope.application.name, user: user}, function () {
|
||||
Notifications.success('Logged out user' + user);
|
||||
$scope.loadUsers();
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('ApplicationClaimsCtrl', function($scope, realm, application, claims,
|
||||
ApplicationClaims,
|
||||
$http, $location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.application = application;
|
||||
$scope.claims = angular.copy(claims);
|
||||
|
||||
$scope.changed = false;
|
||||
|
||||
$scope.$watch('claims', function () {
|
||||
if (!angular.equals($scope.claims, claims)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
$scope.save = function () {
|
||||
ApplicationClaims.update({
|
||||
realm: realm.realm,
|
||||
application: application.name
|
||||
}, $scope.claims, function () {
|
||||
$scope.changed = false;
|
||||
claims = angular.copy($scope.claims);
|
||||
|
||||
Notifications.success("Your claim changes have been saved.");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reset = function () {
|
||||
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/claims");
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
|
||||
module.controller('ApplicationRoleDetailCtrl', function($scope, realm, application, role, roles, applications,
|
||||
Role, ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
|
||||
$http, $location, Dialog, Notifications) {
|
||||
@@ -144,16 +217,43 @@ module.controller('ApplicationInstallationCtrl', function($scope, realm, applica
|
||||
module.controller('ApplicationDetailCtrl', function($scope, realm, application, Application, $location, Dialog, Notifications) {
|
||||
console.log('ApplicationDetailCtrl');
|
||||
|
||||
$scope.clientTypes = [
|
||||
"confidential",
|
||||
"public",
|
||||
"bearer-only"
|
||||
];
|
||||
|
||||
$scope.realm = realm;
|
||||
$scope.create = !application.name;
|
||||
if (!$scope.create) {
|
||||
$scope.application= angular.copy(application);
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
if (application.bearerOnly) {
|
||||
$scope.clientType = $scope.clientTypes[2];
|
||||
} else if (application.publicClient) {
|
||||
$scope.clientType = $scope.clientTypes[1];
|
||||
}
|
||||
} else {
|
||||
$scope.application = {};
|
||||
$scope.application = { enabled: true };
|
||||
$scope.application.webOrigins = [];
|
||||
$scope.application.redirectUris = [];
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
}
|
||||
|
||||
$scope.changeClientType = function() {
|
||||
console.log('Client Type: ' + $scope.clientType);
|
||||
if ($scope.clientType == "confidential") {
|
||||
$scope.application.bearerOnly = false;
|
||||
$scope.application.publicClient = false;
|
||||
} else if ($scope.clientType == "public") {
|
||||
$scope.application.bearerOnly = false;
|
||||
$scope.application.publicClient = true;
|
||||
} else if ($scope.clientType == "bearer-only") {
|
||||
$scope.application.bearerOnly = true;
|
||||
$scope.application.publicClient = false;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function() {
|
||||
@@ -350,3 +450,49 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.controller('ApplicationRevocationCtrl', function($scope, realm, application, Application, ApplicationPushRevocation, $location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.application = application;
|
||||
|
||||
var setNotBefore = function() {
|
||||
if ($scope.application.notBefore == 0) {
|
||||
$scope.notBefore = "None";
|
||||
} else {
|
||||
$scope.notBefore = new Date($scope.application.notBefore * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
setNotBefore();
|
||||
|
||||
var refresh = function() {
|
||||
Application.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
|
||||
$scope.application = updated;
|
||||
setNotBefore();
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.application.notBefore = 0;
|
||||
Application.update({ realm : realm.realm, application: application.name}, $scope.application, function () {
|
||||
$scope.notBefore = "None";
|
||||
Notifications.success('Not Before cleared for application.');
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
$scope.setNotBeforeNow = function() {
|
||||
$scope.application.notBefore = new Date().getTime()/1000;
|
||||
Application.update({ realm : realm.realm, application: $scope.application.name}, $scope.application, function () {
|
||||
Notifications.success('Not Before cleared for application.');
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
$scope.pushRevocation = function() {
|
||||
ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.name}, function () {
|
||||
Notifications.success('Push sent for application.');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
+96
-1
@@ -1,3 +1,37 @@
|
||||
module.controller('OAuthClientClaimsCtrl', function($scope, realm, oauth, claims,
|
||||
OAuthClientClaims,
|
||||
$location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.oauth = oauth;
|
||||
$scope.claims = angular.copy(claims);
|
||||
|
||||
$scope.changed = false;
|
||||
|
||||
$scope.$watch('claims', function () {
|
||||
if (!angular.equals($scope.claims, claims)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
$scope.save = function () {
|
||||
OAuthClientClaims.update({
|
||||
realm: realm.realm,
|
||||
oauth: oauth.id
|
||||
}, $scope.claims, function () {
|
||||
$scope.changed = false;
|
||||
claims = angular.copy($scope.claims);
|
||||
|
||||
Notifications.success("Your claim changes have been saved.");
|
||||
});
|
||||
};
|
||||
|
||||
$scope.reset = function () {
|
||||
$location.url("/realms/" + realm.realm + "/oauth-clients/" + oauth.id + "/claims");
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
module.controller('OAuthClientCredentialsCtrl', function($scope, $location, realm, oauth, OAuthClientCredentials, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.oauth = oauth;
|
||||
@@ -42,12 +76,33 @@ module.controller('OAuthClientListCtrl', function($scope, realm, oauthClients, O
|
||||
module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthClient, $location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.create = !oauth.id;
|
||||
|
||||
$scope.clientTypes = [
|
||||
"confidential",
|
||||
"public"
|
||||
];
|
||||
|
||||
$scope.changeClientType = function() {
|
||||
console.log('Client Type: ' + $scope.clientType);
|
||||
if ($scope.clientType == "confidential") {
|
||||
$scope.oauth.publicClient = false;
|
||||
} else if ($scope.clientType == "public") {
|
||||
$scope.oauth.publicClient = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (!$scope.create) {
|
||||
$scope.oauth= angular.copy(oauth);
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
if (oauth.publicClient) {
|
||||
$scope.clientType = $scope.clientTypes[1];
|
||||
}
|
||||
} else {
|
||||
$scope.oauth = {};
|
||||
$scope.oauth = { enabled: true };
|
||||
$scope.oauth.webOrigins = [];
|
||||
$scope.oauth.redirectUris = [];
|
||||
$scope.clientType = $scope.clientTypes[0];
|
||||
}
|
||||
|
||||
$scope.$watch(function() {
|
||||
@@ -253,3 +308,43 @@ module.controller('OAuthClientInstallationCtrl', function($scope, realm, install
|
||||
$scope.installation = installation;
|
||||
$scope.download = OAuthClientInstallation.url({ realm: $routeParams.realm, oauth: $routeParams.oauth });
|
||||
});
|
||||
|
||||
module.controller('OAuthClientRevocationCtrl', function($scope, realm, oauth, OAuthClient, $location, Dialog, Notifications) {
|
||||
$scope.oauth = oauth;
|
||||
$scope.realm = realm;
|
||||
var setNotBefore = function() {
|
||||
if ($scope.oauth.notBefore == 0) {
|
||||
$scope.notBefore = "None";
|
||||
} else {
|
||||
$scope.notBefore = new Date($scope.oauth.notBefore * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
setNotBefore();
|
||||
|
||||
var refresh = function() {
|
||||
OAuthClient.get({ realm : realm.realm, id: $scope.oauth.id }, function(updated) {
|
||||
$scope.oauth = updated;
|
||||
setNotBefore();
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.oauth.notBefore = 0;
|
||||
OAuthClient.update({ realm : realm.realm, id: $scope.oauth.id}, $scope.oauth, function () {
|
||||
$scope.notBefore = "None";
|
||||
Notifications.success('Not Before cleared for application.');
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
$scope.setNotBeforeNow = function() {
|
||||
$scope.oauth.notBefore = new Date().getTime()/1000;
|
||||
OAuthClient.update({ realm : realm.realm, id: $scope.oauth.id}, $scope.oauth, function () {
|
||||
Notifications.success('Not Before cleared for application.');
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,57 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
|
||||
$http.get('/auth/rest/admin/whoami').success(function(data, status) {
|
||||
Auth.user = data;
|
||||
Auth.loggedIn = true;
|
||||
|
||||
function getAccess(role) {
|
||||
if (!Current.realm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var realmAccess = Auth.user['realm_access'];
|
||||
if (realmAccess) {
|
||||
realmAccess = realmAccess[Current.realm.realm];
|
||||
if (realmAccess) {
|
||||
return realmAccess.indexOf(role) >= 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.access = {
|
||||
createRealm: data.createRealm,
|
||||
|
||||
get viewRealm() {
|
||||
return getAccess('view-realm') || this.manageRealm;
|
||||
},
|
||||
|
||||
get viewApplications() {
|
||||
return getAccess('view-applications') || this.manageApplications;
|
||||
},
|
||||
|
||||
get viewClients() {
|
||||
return getAccess('view-clients') || this.manageClients;
|
||||
},
|
||||
|
||||
get viewUsers() {
|
||||
return getAccess('view-users') || this.manageClients;
|
||||
},
|
||||
|
||||
get manageRealm() {
|
||||
return getAccess('manage-realm');
|
||||
},
|
||||
|
||||
get manageApplications() {
|
||||
return getAccess('manage-applications');
|
||||
},
|
||||
|
||||
get manageClients() {
|
||||
return getAccess('manage-clients');
|
||||
},
|
||||
|
||||
get manageUsers() {
|
||||
return getAccess('manage-users');
|
||||
}
|
||||
}
|
||||
})
|
||||
.error(function(data, status) {
|
||||
Auth.loggedIn = false;
|
||||
@@ -20,15 +71,15 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
|
||||
});
|
||||
});
|
||||
|
||||
module.controller('HomeCtrl', function(Realm, $location) {
|
||||
module.controller('HomeCtrl', function(Realm, Auth, $location) {
|
||||
Realm.query(null, function(realms) {
|
||||
var realm;
|
||||
if (realms.length == 1) {
|
||||
realm = realms[0].realm;
|
||||
} else if (realms.length == 2) {
|
||||
if (realms[0].realm == 'keycloak-admin') {
|
||||
if (realms[0].realm == Auth.user.realm) {
|
||||
realm = realms[1].realm;
|
||||
} else if (realms[1].realm == 'administration') {
|
||||
} else if (realms[1].realm == Auth.user.realm) {
|
||||
realm = realms[0].realm;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +113,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
|
||||
}
|
||||
});
|
||||
|
||||
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications) {
|
||||
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications, Auth) {
|
||||
console.log('RealmCreateCtrl');
|
||||
|
||||
Current.realm = null;
|
||||
@@ -100,9 +151,23 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||
//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");
|
||||
}).success(function(data, status, headers) {
|
||||
Realm.query(function(data) {
|
||||
Current.realms = data;
|
||||
|
||||
$http.get('/auth/rest/admin/whoami').success(function(user) {
|
||||
Auth.user = user;
|
||||
|
||||
Notifications.success("The realm has been uploaded.");
|
||||
|
||||
var location = headers('Location');
|
||||
if (location) {
|
||||
$location.url("/realms/" + location.substring(location.lastIndexOf('/') + 1));
|
||||
} else {
|
||||
$location.url("/realms");
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.error(function() {
|
||||
Notifications.error("The realm can not be uploaded. Please verify the file.");
|
||||
@@ -123,16 +188,16 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||
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() {
|
||||
Realm.create(realmCopy, function() {
|
||||
Realm.query(function(data) {
|
||||
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.");
|
||||
|
||||
$http.get('/auth/rest/admin/whoami').success(function(user) {
|
||||
Auth.user = user;
|
||||
|
||||
$location.url("/realms/" + realmCopy.realm);
|
||||
Notifications.success("The realm has been created.");
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -445,7 +510,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
|
||||
// Update/save the selected application with new default roles.
|
||||
Application.update({
|
||||
realm: $scope.realm.realm,
|
||||
id: $scope.application.name
|
||||
application: $scope.application.name
|
||||
}, $scope.application, function () {
|
||||
Notifications.success("Your changes have been saved to the application.");
|
||||
});
|
||||
@@ -469,7 +534,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
|
||||
// Update/save the selected application with new default roles.
|
||||
Application.update({
|
||||
realm: $scope.realm.realm,
|
||||
id: $scope.application.name
|
||||
application: $scope.application.name
|
||||
}, $scope.application, function () {
|
||||
Notifications.success("Your changes have been saved to the application.");
|
||||
});
|
||||
@@ -543,10 +608,22 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||
|
||||
$scope.realm = realm;
|
||||
|
||||
$scope.realm.tokenLifespanUnit = TimeUnit.autoUnit(realm.tokenLifespan);
|
||||
$scope.realm.tokenLifespan = TimeUnit.toUnit(realm.tokenLifespan, $scope.realm.tokenLifespanUnit);
|
||||
$scope.$watch('realm.tokenLifespanUnit', function(to, from) {
|
||||
$scope.realm.tokenLifespan = TimeUnit.convert($scope.realm.tokenLifespan, from, to);
|
||||
$scope.realm.accessTokenLifespanUnit = TimeUnit.autoUnit(realm.accessTokenLifespan);
|
||||
$scope.realm.accessTokenLifespan = TimeUnit.toUnit(realm.accessTokenLifespan, $scope.realm.accessTokenLifespanUnit);
|
||||
$scope.$watch('realm.accessTokenLifespanUnit', function(to, from) {
|
||||
$scope.realm.accessTokenLifespan = TimeUnit.convert($scope.realm.accessTokenLifespan, from, to);
|
||||
});
|
||||
|
||||
$scope.realm.centralLoginLifespanUnit = TimeUnit.autoUnit(realm.centralLoginLifespan);
|
||||
$scope.realm.centralLoginLifespan = TimeUnit.toUnit(realm.centralLoginLifespan, $scope.realm.centralLoginLifespanUnit);
|
||||
$scope.$watch('realm.centralLoginLifespanUnit', function(to, from) {
|
||||
$scope.realm.centralLoginLifespan = TimeUnit.convert($scope.realm.centralLoginLifespan, from, to);
|
||||
});
|
||||
|
||||
$scope.realm.refreshTokenLifespanUnit = TimeUnit.autoUnit(realm.refreshTokenLifespan);
|
||||
$scope.realm.refreshTokenLifespan = TimeUnit.toUnit(realm.refreshTokenLifespan, $scope.realm.refreshTokenLifespanUnit);
|
||||
$scope.$watch('realm.refreshTokenLifespanUnit', function(to, from) {
|
||||
$scope.realm.refreshTokenLifespan = TimeUnit.convert($scope.realm.refreshTokenLifespan, from, to);
|
||||
});
|
||||
|
||||
$scope.realm.accessCodeLifespanUnit = TimeUnit.autoUnit(realm.accessCodeLifespan);
|
||||
@@ -573,11 +650,15 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||
|
||||
$scope.save = function() {
|
||||
var realmCopy = angular.copy($scope.realm);
|
||||
delete realmCopy["tokenLifespanUnit"];
|
||||
delete realmCopy["accessTokenLifespanUnit"];
|
||||
delete realmCopy["refreshTokenLifespanUnit"];
|
||||
delete realmCopy["accessCodeLifespanUnit"];
|
||||
delete realmCopy["centralLoginLifespanUnit"];
|
||||
delete realmCopy["accessCodeLifespanUserActionUnit"];
|
||||
|
||||
realmCopy.tokenLifespan = TimeUnit.toSeconds($scope.realm.tokenLifespan, $scope.realm.tokenLifespanUnit)
|
||||
realmCopy.accessTokenLifespan = TimeUnit.toSeconds($scope.realm.accessTokenLifespan, $scope.realm.accessTokenLifespanUnit)
|
||||
realmCopy.centralLoginLifespan = TimeUnit.toSeconds($scope.realm.centralLoginLifespan, $scope.realm.centralLoginLifespanUnit)
|
||||
realmCopy.refreshTokenLifespan = TimeUnit.toSeconds($scope.realm.refreshTokenLifespan, $scope.realm.refreshTokenLifespanUnit)
|
||||
realmCopy.accessCodeLifespan = TimeUnit.toSeconds($scope.realm.accessCodeLifespan, $scope.realm.accessCodeLifespanUnit)
|
||||
realmCopy.accessCodeLifespanUserAction = TimeUnit.toSeconds($scope.realm.accessCodeLifespanUserAction, $scope.realm.accessCodeLifespanUserActionUnit)
|
||||
|
||||
@@ -609,6 +690,69 @@ module.controller('RealmKeysDetailCtrl', function($scope, Realm, realm, $http, $
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('RealmSessionStatsCtrl', function($scope, realm, stats, RealmSessionStats, RealmLogoutAll, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.stats = stats;
|
||||
|
||||
console.log(stats);
|
||||
|
||||
$scope.logoutAll = function() {
|
||||
RealmLogoutAll.save({realm : realm.realm}, function () {
|
||||
Notifications.success('Logged out all users');
|
||||
RealmSessionStats.get({realm: realm.realm}, function(updated) {
|
||||
Notifications.success('Logged out all users');
|
||||
$scope.stats = updated;
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevocation, realm, $http, $location, Dialog, Notifications) {
|
||||
$scope.realm = angular.copy(realm);
|
||||
|
||||
var setNotBefore = function() {
|
||||
if ($scope.realm.notBefore == 0) {
|
||||
$scope.notBefore = "None";
|
||||
} else {
|
||||
$scope.notBefore = new Date($scope.realm.notBefore * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
setNotBefore();
|
||||
|
||||
var reset = function() {
|
||||
Realm.get({ id : realm.realm }, function(updated) {
|
||||
$scope.realm = updated;
|
||||
setNotBefore();
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
Realm.update({ realm: realm.realm, notBefore : 0 }, function () {
|
||||
$scope.notBefore = "None";
|
||||
Notifications.success('Not Before cleared for realm.');
|
||||
reset();
|
||||
});
|
||||
}
|
||||
$scope.setNotBeforeNow = function() {
|
||||
Realm.update({ realm: realm.realm, notBefore : new Date().getTime()/1000}, function () {
|
||||
Notifications.success('Not Before cleared for realm.');
|
||||
reset();
|
||||
});
|
||||
}
|
||||
$scope.pushRevocation = function() {
|
||||
RealmPushRevocation.save({ realm: realm.realm}, function () {
|
||||
Notifications.success('Push sent for realm.');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
module.controller('RoleListCtrl', function($scope, $location, realm, roles) {
|
||||
|
||||
$scope.realm = realm;
|
||||
|
||||
@@ -118,6 +118,35 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
|
||||
|
||||
});
|
||||
|
||||
module.controller('UserSessionsCtrl', function($scope, realm, user, stats, UserLogout, ApplicationLogoutUser, UserSessionStats, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.user = user;
|
||||
$scope.stats = stats;
|
||||
|
||||
$scope.logoutAll = function() {
|
||||
UserLogout.save({realm : realm.realm, user: user.username}, function () {
|
||||
Notifications.success('Logged out user in all applications');
|
||||
UserSessionStats.get({realm: realm.realm, user: user.username}, function(updated) {
|
||||
$scope.stats = updated;
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
$scope.logoutApplication = function(app) {
|
||||
console.log('log user out of app: ' + app);
|
||||
ApplicationLogoutUser.save({realm : realm.realm, application: app, user: user.username}, function () {
|
||||
Notifications.success('Logged out user from application');
|
||||
UserSessionStats.get({realm: realm.realm, user: user.username}, function(updated) {
|
||||
$scope.stats = updated;
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
module.controller('UserListCtrl', function($scope, realm, User) {
|
||||
$scope.realm = realm;
|
||||
$scope.searchQuery = function() {
|
||||
@@ -143,41 +172,20 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
|
||||
$scope.user = angular.copy(user);
|
||||
$scope.create = !user.username;
|
||||
|
||||
if ($scope.create) {
|
||||
$scope.user.enabled = true;
|
||||
}
|
||||
|
||||
$scope.changed = false; // $scope.create;
|
||||
|
||||
// ID - Name map for required actions. IDs are enum names.
|
||||
var userReqActionList = [
|
||||
$scope.userReqActionList = [
|
||||
{id: "VERIFY_EMAIL", text: "Verify Email"},
|
||||
{id: "UPDATE_PROFILE", text: "Update Profile"},
|
||||
{id: "CONFIGURE_TOTP", text: "Configure Totp"},
|
||||
{id: "UPDATE_PASSWORD", text: "Update Password"}
|
||||
];
|
||||
|
||||
// Options for the req actions tag selector
|
||||
$scope.userReqActionsOptions = {
|
||||
'multiple' : true,
|
||||
'tags' : userReqActionList
|
||||
};
|
||||
|
||||
// Model for the req actions tag selector
|
||||
$scope.userActions = [];
|
||||
for (var i = 0; i < userReqActionList.length; i++){
|
||||
var action = userReqActionList[i];
|
||||
|
||||
if ($scope.user.requiredActions && $scope.user.requiredActions.indexOf(action.id) > -1){
|
||||
$scope.userActions.push({id: action.id, text: action.text});
|
||||
}
|
||||
}
|
||||
|
||||
// Watching ui-select2 model to properly format the req actions for user
|
||||
$scope.$watch("userActions", function(newValue, oldValue) {
|
||||
$scope.user.requiredActions = [];
|
||||
for (var i=0; i < newValue.length; i++){
|
||||
var action = newValue[i];
|
||||
$scope.user.requiredActions.push(action.id);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('user', function() {
|
||||
if (!angular.equals($scope.user, user)) {
|
||||
$scope.changed = true;
|
||||
|
||||
@@ -48,20 +48,37 @@ module.factory('RealmLoader', function(Loader, Realm, $route, $q) {
|
||||
});
|
||||
|
||||
module.factory('UserListLoader', function(Loader, User, $route, $q) {
|
||||
return Loader.query(User, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm
|
||||
}
|
||||
});
|
||||
return Loader.query(User, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $route, $q) {
|
||||
return Loader.get(RealmSessionStats, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('UserLoader', function(Loader, User, $route, $q) {
|
||||
return Loader.get(User, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
userId : $route.current.params.user
|
||||
}
|
||||
});
|
||||
return Loader.get(User, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
userId : $route.current.params.user
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('UserSessionStatsLoader', function(Loader, UserSessionStats, $route, $q) {
|
||||
return Loader.get(UserSessionStats, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
user : $route.current.params.user
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RoleLoader', function(Loader, Role, $route, $q) {
|
||||
@@ -91,6 +108,24 @@ module.factory('ApplicationRoleLoader', function(Loader, ApplicationRole, $route
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationSessionStatsLoader', function(Loader, ApplicationSessionStats, $route, $q) {
|
||||
return Loader.get(ApplicationSessionStats, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
application : $route.current.params.application
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationClaimsLoader', function(Loader, ApplicationClaims, $route, $q) {
|
||||
return Loader.get(ApplicationClaims, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
application : $route.current.params.application
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationInstallationLoader', function(Loader, ApplicationInstallation, $route, $q) {
|
||||
return Loader.get(ApplicationInstallation, function() {
|
||||
return {
|
||||
@@ -149,6 +184,16 @@ module.factory('OAuthClientLoader', function(Loader, OAuthClient, $route, $q) {
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientClaimsLoader', function(Loader, OAuthClientClaims, $route, $q) {
|
||||
return Loader.get(OAuthClientClaims, function() {
|
||||
return {
|
||||
realm : $route.current.params.realm,
|
||||
oauth : $route.current.params.oauth
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
module.factory('OAuthClientListLoader', function(Loader, OAuthClient, $route, $q) {
|
||||
return Loader.query(OAuthClient, function() {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('keycloak.services', [ 'ngResource' ]);
|
||||
var module = angular.module('keycloak.services', [ 'ngResource', 'ngRoute' ]);
|
||||
|
||||
module.service('Dialog', function($dialog) {
|
||||
var dialog = {};
|
||||
@@ -147,14 +147,27 @@ module.factory('ServerInfo', function($resource) {
|
||||
});
|
||||
|
||||
module.factory('User', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/users/:userId', {
|
||||
realm : '@realm',
|
||||
userId : '@userId'
|
||||
}, {
|
||||
return $resource('/auth/rest/admin/realms/:realm/users/:userId', {
|
||||
realm : '@realm',
|
||||
userId : '@userId'
|
||||
}, {
|
||||
update : {
|
||||
method : 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('UserSessionStats', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/users/:user/session-stats', {
|
||||
realm : '@realm',
|
||||
user : '@user'
|
||||
});
|
||||
});
|
||||
module.factory('UserLogout', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/users/:user/logout', {
|
||||
realm : '@realm',
|
||||
user : '@user'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('UserCredentials', function($resource) {
|
||||
@@ -235,6 +248,19 @@ module.factory('RoleRealmComposites', function($resource) {
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RealmPushRevocation', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/push-revocation', {
|
||||
realm : '@realm'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RealmSessionStats', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/session-stats', {
|
||||
realm : '@realm'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
module.factory('RoleApplicationComposites', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
|
||||
realm : '@realm',
|
||||
@@ -451,6 +477,58 @@ module.factory('ApplicationRole', function($resource) {
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationClaims', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/claims', {
|
||||
realm : '@realm',
|
||||
application : "@application"
|
||||
}, {
|
||||
update : {
|
||||
method : 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationSessionStats', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/session-stats', {
|
||||
realm : '@realm',
|
||||
application : "@application"
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationSessionStatsWithUsers', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/session-stats?users=true', {
|
||||
realm : '@realm',
|
||||
application : "@application"
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationLogoutAll', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/logout-all', {
|
||||
realm : '@realm',
|
||||
application : "@application"
|
||||
});
|
||||
});
|
||||
module.factory('ApplicationLogoutUser', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/logout-user/:user', {
|
||||
realm : '@realm',
|
||||
application : "@application",
|
||||
user : "@user"
|
||||
});
|
||||
});
|
||||
module.factory('RealmLogoutAll', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/logout-all', {
|
||||
realm : '@realm'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('ApplicationPushRevocation', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application/push-revocation', {
|
||||
realm : '@realm',
|
||||
application : "@application"
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.factory('Application', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/applications/:application', {
|
||||
@@ -516,6 +594,18 @@ module.factory('OAuthClient', function($resource) {
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('OAuthClientClaims', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/claims', {
|
||||
realm : '@realm',
|
||||
oauth : "@oauth"
|
||||
}, {
|
||||
update : {
|
||||
method : 'PUT'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
module.factory('OAuthClientCredentials', function($resource) {
|
||||
return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/client-secret', {
|
||||
realm : '@realm',
|
||||
|
||||
Vendored
Executable → Regular
+22
-5
@@ -1,14 +1,25 @@
|
||||
/**
|
||||
* @license AngularJS v1.0.7
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.2.13
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
'use strict';
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name ngCookies
|
||||
* @description
|
||||
*
|
||||
* # ngCookies
|
||||
*
|
||||
* The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
|
||||
*
|
||||
* {@installModule cookies}
|
||||
*
|
||||
* <div doc-module-components="ngCookies"></div>
|
||||
*
|
||||
* See {@link ngCookies.$cookies `$cookies`} and
|
||||
* {@link ngCookies.$cookieStore `$cookieStore`} for usage.
|
||||
*/
|
||||
|
||||
|
||||
@@ -24,6 +35,8 @@ angular.module('ngCookies', ['ng']).
|
||||
* Only a simple Object is exposed and by adding or removing properties to/from
|
||||
* this object, new cookies are created/deleted at the end of current $eval.
|
||||
*
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -68,7 +81,8 @@ angular.module('ngCookies', ['ng']).
|
||||
|
||||
|
||||
/**
|
||||
* Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
|
||||
* Pushes all the cookies from the service to the browser and verifies if all cookies were
|
||||
* stored.
|
||||
*/
|
||||
function push() {
|
||||
var name,
|
||||
@@ -128,6 +142,9 @@ angular.module('ngCookies', ['ng']).
|
||||
* Provides a key-value (string-object) storage, that is backed by session cookies.
|
||||
* Objects put or retrieved from this storage are automatically serialized or
|
||||
* deserialized by angular's toJson/fromJson.
|
||||
*
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
* @example
|
||||
*/
|
||||
factory('$cookieStore', ['$cookies', function($cookies) {
|
||||
|
||||
Vendored
Executable → Regular
+153
-20
@@ -1,10 +1,84 @@
|
||||
/**
|
||||
* @license AngularJS v1.0.7
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.2.13
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
(
|
||||
(function() {'use strict';
|
||||
|
||||
/**
|
||||
* @description
|
||||
*
|
||||
* This object provides a utility for producing rich Error messages within
|
||||
* Angular. It can be called as follows:
|
||||
*
|
||||
* var exampleMinErr = minErr('example');
|
||||
* throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
|
||||
*
|
||||
* The above creates an instance of minErr in the example namespace. The
|
||||
* resulting error will have a namespaced error code of example.one. The
|
||||
* resulting error will replace {0} with the value of foo, and {1} with the
|
||||
* value of bar. The object is not restricted in the number of arguments it can
|
||||
* take.
|
||||
*
|
||||
* If fewer arguments are specified than necessary for interpolation, the extra
|
||||
* interpolation markers will be preserved in the final string.
|
||||
*
|
||||
* Since data will be parsed statically during a build step, some restrictions
|
||||
* are applied with respect to how minErr instances are created and called.
|
||||
* Instances should have names of the form namespaceMinErr for a minErr created
|
||||
* using minErr('namespace') . Error codes, namespaces and template strings
|
||||
* should all be static strings, not variables or general expressions.
|
||||
*
|
||||
* @param {string} module The namespace to use for the new minErr instance.
|
||||
* @returns {function(string, string, ...): Error} instance
|
||||
*/
|
||||
|
||||
function minErr(module) {
|
||||
return function () {
|
||||
var code = arguments[0],
|
||||
prefix = '[' + (module ? module + ':' : '') + code + '] ',
|
||||
template = arguments[1],
|
||||
templateArgs = arguments,
|
||||
stringify = function (obj) {
|
||||
if (typeof obj === 'function') {
|
||||
return obj.toString().replace(/ \{[\s\S]*$/, '');
|
||||
} else if (typeof obj === 'undefined') {
|
||||
return 'undefined';
|
||||
} else if (typeof obj !== 'string') {
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
message, i;
|
||||
|
||||
message = prefix + template.replace(/\{\d+\}/g, function (match) {
|
||||
var index = +match.slice(1, -1), arg;
|
||||
|
||||
if (index + 2 < templateArgs.length) {
|
||||
arg = templateArgs[index + 2];
|
||||
if (typeof arg === 'function') {
|
||||
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
|
||||
} else if (typeof arg === 'undefined') {
|
||||
return 'undefined';
|
||||
} else if (typeof arg !== 'string') {
|
||||
return toJson(arg);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
|
||||
message = message + '\nhttp://errors.angularjs.org/1.2.13/' +
|
||||
(module ? module + '/' : '') + code;
|
||||
for (i = 2; i < arguments.length; i++) {
|
||||
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
||||
encodeURIComponent(stringify(arguments[i]));
|
||||
}
|
||||
|
||||
return new Error(message);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc interface
|
||||
@@ -16,11 +90,19 @@
|
||||
|
||||
function setupModuleLoader(window) {
|
||||
|
||||
var $injectorMinErr = minErr('$injector');
|
||||
var ngMinErr = minErr('ng');
|
||||
|
||||
function ensure(obj, name, factory) {
|
||||
return obj[name] || (obj[name] = factory());
|
||||
}
|
||||
|
||||
return ensure(ensure(window, 'angular', Object), 'module', function() {
|
||||
var angular = ensure(window, 'angular', Object);
|
||||
|
||||
// We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
|
||||
angular.$$minErr = angular.$$minErr || minErr;
|
||||
|
||||
return ensure(angular, 'module', function() {
|
||||
/** @type {Object.<string, angular.Module>} */
|
||||
var modules = {};
|
||||
|
||||
@@ -29,15 +111,19 @@ function setupModuleLoader(window) {
|
||||
* @name angular.module
|
||||
* @description
|
||||
*
|
||||
* The `angular.module` is a global place for creating and registering Angular modules. All
|
||||
* modules (angular core or 3rd party) that should be available to an application must be
|
||||
* The `angular.module` is a global place for creating, registering and retrieving Angular
|
||||
* modules.
|
||||
* All modules (angular core or 3rd party) that should be available to an application must be
|
||||
* registered using this mechanism.
|
||||
*
|
||||
* When passed two or more arguments, a new module is created. If passed only one argument, an
|
||||
* existing module (the name passed as the first argument to `module`) is retrieved.
|
||||
*
|
||||
*
|
||||
* # Module
|
||||
*
|
||||
* A module is a collocation of services, directives, filters, and configuration information. Module
|
||||
* is used to configure the {@link AUTO.$injector $injector}.
|
||||
* A module is a collection of services, directives, filters, and configuration information.
|
||||
* `angular.module` is used to configure the {@link AUTO.$injector $injector}.
|
||||
*
|
||||
* <pre>
|
||||
* // Create a new module
|
||||
@@ -48,7 +134,6 @@ function setupModuleLoader(window) {
|
||||
*
|
||||
* // configure existing services inside initialization blocks.
|
||||
* myModule.config(function($locationProvider) {
|
||||
'use strict';
|
||||
* // Configure existing providers
|
||||
* $locationProvider.hashPrefix('!');
|
||||
* });
|
||||
@@ -65,19 +150,28 @@ function setupModuleLoader(window) {
|
||||
* {@link angular.bootstrap} to simplify this process for you.
|
||||
*
|
||||
* @param {!string} name The name of the module to create or retrieve.
|
||||
* @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
|
||||
* the module is being retrieved for further configuration.
|
||||
* @param {Array.<string>=} requires If specified then new module is being created. If
|
||||
* unspecified then the the module is being retrieved for further configuration.
|
||||
* @param {Function} configFn Optional configuration function for the module. Same as
|
||||
* {@link angular.Module#config Module#config()}.
|
||||
* {@link angular.Module#methods_config Module#config()}.
|
||||
* @returns {module} new module with the {@link angular.Module} api.
|
||||
*/
|
||||
return function module(name, requires, configFn) {
|
||||
var assertNotHasOwnProperty = function(name, context) {
|
||||
if (name === 'hasOwnProperty') {
|
||||
throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
|
||||
}
|
||||
};
|
||||
|
||||
assertNotHasOwnProperty(name, 'module');
|
||||
if (requires && modules.hasOwnProperty(name)) {
|
||||
modules[name] = null;
|
||||
}
|
||||
return ensure(modules, name, function() {
|
||||
if (!requires) {
|
||||
throw Error('No module: ' + name);
|
||||
throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
|
||||
"the module name or forgot to load it. If registering a module ensure that you " +
|
||||
"specify the dependencies as the second argument.", name);
|
||||
}
|
||||
|
||||
/** @type {!Array.<Array.<*>>} */
|
||||
@@ -100,7 +194,8 @@ function setupModuleLoader(window) {
|
||||
* @propertyOf angular.Module
|
||||
* @returns {Array.<string>} List of module names which must be loaded before this module.
|
||||
* @description
|
||||
* Holds the list of modules which the injector will load before the current module is loaded.
|
||||
* Holds the list of modules which the injector will load before the current module is
|
||||
* loaded.
|
||||
*/
|
||||
requires: requires,
|
||||
|
||||
@@ -119,7 +214,8 @@ function setupModuleLoader(window) {
|
||||
* @name angular.Module#provider
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name service name
|
||||
* @param {Function} providerType Construction function for creating new instance of the service.
|
||||
* @param {Function} providerType Construction function for creating new instance of the
|
||||
* service.
|
||||
* @description
|
||||
* See {@link AUTO.$provide#provider $provide.provider()}.
|
||||
*/
|
||||
@@ -170,6 +266,40 @@ function setupModuleLoader(window) {
|
||||
*/
|
||||
constant: invokeLater('$provide', 'constant', 'unshift'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#animation
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name animation name
|
||||
* @param {Function} animationFactory Factory function for creating new instance of an
|
||||
* animation.
|
||||
* @description
|
||||
*
|
||||
* **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
|
||||
*
|
||||
*
|
||||
* Defines an animation hook that can be later used with
|
||||
* {@link ngAnimate.$animate $animate} service and directives that use this service.
|
||||
*
|
||||
* <pre>
|
||||
* module.animation('.animation-name', function($inject1, $inject2) {
|
||||
* return {
|
||||
* eventName : function(element, done) {
|
||||
* //code to run the animation
|
||||
* //once complete, then run done()
|
||||
* return function cancellationFunction(element) {
|
||||
* //code to cancel the animation
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* </pre>
|
||||
*
|
||||
* See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
|
||||
* {@link ngAnimate ngAnimate module} for more information.
|
||||
*/
|
||||
animation: invokeLater('$animateProvider', 'register'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#filter
|
||||
@@ -185,7 +315,8 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#controller
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name Controller name.
|
||||
* @param {string|Object} name Controller name, or an object map of controllers where the
|
||||
* keys are the names and the values are the constructors.
|
||||
* @param {Function} constructor Controller constructor function.
|
||||
* @description
|
||||
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
|
||||
@@ -196,11 +327,12 @@ function setupModuleLoader(window) {
|
||||
* @ngdoc method
|
||||
* @name angular.Module#directive
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name directive name
|
||||
* @param {string|Object} name Directive name, or an object map of directives where the
|
||||
* keys are the names and the values are the factories.
|
||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
||||
* directives.
|
||||
* @description
|
||||
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
||||
* See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
|
||||
*/
|
||||
directive: invokeLater('$compileProvider', 'directive'),
|
||||
|
||||
@@ -247,7 +379,7 @@ function setupModuleLoader(window) {
|
||||
return function() {
|
||||
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
|
||||
return moduleInstance;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -255,7 +387,8 @@ function setupModuleLoader(window) {
|
||||
|
||||
}
|
||||
|
||||
)(window);
|
||||
setupModuleLoader(window);
|
||||
})(window);
|
||||
|
||||
/**
|
||||
* Closure compiler type information
|
||||
|
||||
Vendored
Executable → Regular
+756
-408
File diff suppressed because it is too large.
Load diff
Vendored
Executable → Regular
+302
-163
@@ -1,15 +1,68 @@
|
||||
/**
|
||||
* @license AngularJS v1.0.7
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.2.13
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
'use strict';
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
var $resourceMinErr = angular.$$minErr('$resource');
|
||||
|
||||
// Helper functions and regex to lookup a dotted path on an object
|
||||
// stopping at undefined/null. The path must be composed of ASCII
|
||||
// identifiers (just like $parse)
|
||||
var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
|
||||
|
||||
function isValidDottedPath(path) {
|
||||
return (path != null && path !== '' && path !== 'hasOwnProperty' &&
|
||||
MEMBER_NAME_REGEX.test('.' + path));
|
||||
}
|
||||
|
||||
function lookupDottedPath(obj, path) {
|
||||
if (!isValidDottedPath(path)) {
|
||||
throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
|
||||
}
|
||||
var keys = path.split('.');
|
||||
for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
|
||||
var key = keys[i];
|
||||
obj = (obj !== null) ? obj[key] : undefined;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of an object and clear other fields from the destination
|
||||
*/
|
||||
function shallowClearAndCopy(src, dst) {
|
||||
dst = dst || {};
|
||||
|
||||
angular.forEach(dst, function(value, key){
|
||||
delete dst[key];
|
||||
});
|
||||
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name ngResource
|
||||
* @description
|
||||
*
|
||||
* # ngResource
|
||||
*
|
||||
* The `ngResource` module provides interaction support with RESTful services
|
||||
* via the $resource service.
|
||||
*
|
||||
* {@installModule resource}
|
||||
*
|
||||
* <div doc-module-components="ngResource"></div>
|
||||
*
|
||||
* See {@link ngResource.$resource `$resource`} for usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -24,24 +77,22 @@
|
||||
* The returned resource object has action methods which provide high-level behaviors without
|
||||
* the need to interact with the low level {@link ng.$http $http} service.
|
||||
*
|
||||
* # Installation
|
||||
* To use $resource make sure you have included the `angular-resource.js` that comes in Angular
|
||||
* package. You can also find this file on Google CDN, bower as well as at
|
||||
* {@link http://code.angularjs.org/ code.angularjs.org}.
|
||||
* Requires the {@link ngResource `ngResource`} module to be installed.
|
||||
*
|
||||
* Finally load the module in your application:
|
||||
* @param {string} url A parametrized URL template with parameters prefixed by `:` as in
|
||||
* `/user/:username`. If you are using a URL with a port number (e.g.
|
||||
* `http://example.com:8080/api`), it will be respected.
|
||||
*
|
||||
* angular.module('app', ['ngResource']);
|
||||
*
|
||||
* and you are ready to get started!
|
||||
*
|
||||
* @param {string} url A parameterized URL template with parameters prefixed by `:` as in
|
||||
* `/user/:username`. If you are using a URL with a port number (e.g.
|
||||
* `http://example.com:8080/api`), you'll need to escape the colon character before the port
|
||||
* number, like this: `$resource('http://example.com\\:8080/api')`.
|
||||
* If you are using a url with a suffix, just add the suffix, like this:
|
||||
* `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
|
||||
* or even `$resource('http://example.com/resource/:resource_id.:format')`
|
||||
* If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
|
||||
* collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
|
||||
* can escape it with `/\.`.
|
||||
*
|
||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
||||
* `actions` methods.
|
||||
* `actions` methods. If any of the parameter value is a function, it will be executed every time
|
||||
* when a param value needs to be obtained for a request (unless the param was overridden).
|
||||
*
|
||||
* Each key value in the parameter object is first bound to url template if present and then any
|
||||
* excess keys are appended to the url search query after the `?`.
|
||||
@@ -53,21 +104,48 @@
|
||||
* the data object (useful for non-GET operations).
|
||||
*
|
||||
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend the
|
||||
* default set of resource actions. The declaration should be created in the following format:
|
||||
* default set of resource actions. The declaration should be created in the format of {@link
|
||||
* ng.$http#usage_parameters $http.config}:
|
||||
*
|
||||
* {action1: {method:?, params:?, isArray:?},
|
||||
* action2: {method:?, params:?, isArray:?},
|
||||
* {action1: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* action2: {method:?, params:?, isArray:?, headers:?, ...},
|
||||
* ...}
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
* - `action` – {string} – The name of action. This name becomes the name of the method on your
|
||||
* resource object.
|
||||
* - `method` – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, `DELETE`,
|
||||
* and `JSONP`
|
||||
* - `params` – {object=} – Optional set of pre-bound parameters for this action.
|
||||
* - isArray – {boolean=} – If true then the returned object for this action is an array, see
|
||||
* `returns` section.
|
||||
* - **`action`** – {string} – The name of action. This name becomes the name of the method on
|
||||
* your resource object.
|
||||
* - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`,
|
||||
* `DELETE`, and `JSONP`.
|
||||
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
|
||||
* the parameter value is a function, it will be executed every time when a param value needs to
|
||||
* be obtained for a request (unless the param was overridden).
|
||||
* - **`url`** – {string} – action specific `url` override. The url templating is supported just
|
||||
* like for the resource-level urls.
|
||||
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
|
||||
* see `returns` section.
|
||||
* - **`transformRequest`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* request body and headers and returns its transformed (typically serialized) version.
|
||||
* - **`transformResponse`** –
|
||||
* `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
|
||||
* transform function or an array of such functions. The transform function takes the http
|
||||
* response body and headers and returns its transformed (typically deserialized) version.
|
||||
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
|
||||
* GET request, otherwise if a cache instance built with
|
||||
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
||||
* caching.
|
||||
* - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
|
||||
* should abort the request when resolved.
|
||||
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
|
||||
* XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
|
||||
* requests with credentials} for more information.
|
||||
* - **`responseType`** - `{string}` - see {@link
|
||||
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
|
||||
* - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
|
||||
* `response` and `responseError`. Both `response` and `responseError` interceptors get called
|
||||
* with `http response` object. See {@link ng.$http $http interceptors}.
|
||||
*
|
||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
||||
* optionally extended with custom `actions`. The default set contains these actions:
|
||||
@@ -97,7 +175,7 @@
|
||||
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
|
||||
* object results in no rendering, once the data arrives from the server then the object is
|
||||
* populated with the data and the view automatically re-renders itself showing the new data. This
|
||||
* means that in most case one never has to write a callback function for the action methods.
|
||||
* means that in most cases one never has to write a callback function for the action methods.
|
||||
*
|
||||
* The action methods on the class object or instance object can be invoked with the following
|
||||
* parameters:
|
||||
@@ -106,6 +184,28 @@
|
||||
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
||||
*
|
||||
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
|
||||
* with (httpResponse) argument.
|
||||
*
|
||||
* Class actions return empty instance (with additional properties below).
|
||||
* Instance actions return promise of the action.
|
||||
*
|
||||
* The Resource instances and collection have these additional properties:
|
||||
*
|
||||
* - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
|
||||
* instance or collection.
|
||||
*
|
||||
* On success, the promise is resolved with the same resource instance or collection object,
|
||||
* updated with data from server. This makes it easy to use in
|
||||
* {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
|
||||
* rendering until the resource(s) are loaded.
|
||||
*
|
||||
* On failure, the promise is resolved with the {@link ng.$http http response} object, without
|
||||
* the `resource` property.
|
||||
*
|
||||
* - `$resolved`: `true` after first server interaction is completed (either with success or
|
||||
* rejection), `false` before that. Knowing if the Resource has been resolved is useful in
|
||||
* data-binding.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
@@ -142,14 +242,15 @@
|
||||
newCard.name = "Mike Smith";
|
||||
newCard.$save();
|
||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
||||
// server returns: {id:789, number:'01234', name: 'Mike Smith'};
|
||||
// server returns: {id:789, number:'0123', name: 'Mike Smith'};
|
||||
expect(newCard.id).toEqual(789);
|
||||
* </pre>
|
||||
*
|
||||
* The object returned from this function execution is a resource "class" which has "static" method
|
||||
* for each action in the definition.
|
||||
*
|
||||
* Calling these methods invoke `$http` on the `url` template with the given `method` and `params`.
|
||||
* Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
|
||||
* `headers`.
|
||||
* When the data is returned from the server then the object is an instance of the resource type and
|
||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
||||
* operations (create, read, update, delete) on server-side data.
|
||||
@@ -162,7 +263,7 @@
|
||||
});
|
||||
</pre>
|
||||
*
|
||||
* It's worth noting that the success callback for `get`, `query` and other method gets passed
|
||||
* It's worth noting that the success callback for `get`, `query` and other methods gets passed
|
||||
* in the response that came from the server as well as $http header getter function, so one
|
||||
* could rewrite the above example and get access to http headers as:
|
||||
*
|
||||
@@ -177,56 +278,38 @@
|
||||
});
|
||||
</pre>
|
||||
|
||||
* # Buzz client
|
||||
|
||||
Let's look at what a buzz client created with the `$resource` service looks like:
|
||||
<doc:example>
|
||||
<doc:source jsfiddle="false">
|
||||
<script>
|
||||
function BuzzController($resource) {
|
||||
this.userId = 'googlebuzz';
|
||||
this.Activity = $resource(
|
||||
'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
|
||||
{alt:'json', callback:'JSON_CALLBACK'},
|
||||
{get:{method:'JSONP', params:{visibility:'@self'}}, replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}}}
|
||||
);
|
||||
}
|
||||
|
||||
BuzzController.prototype = {
|
||||
fetch: function() {
|
||||
this.activities = this.Activity.get({userId:this.userId});
|
||||
},
|
||||
expandReplies: function(activity) {
|
||||
activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id});
|
||||
}
|
||||
};
|
||||
BuzzController.$inject = ['$resource'];
|
||||
</script>
|
||||
|
||||
<div ng-controller="BuzzController">
|
||||
<input ng-model="userId"/>
|
||||
<button ng-click="fetch()">fetch</button>
|
||||
<hr/>
|
||||
<div ng-repeat="item in activities.data.items">
|
||||
<h1 style="font-size: 15px;">
|
||||
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
||||
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
|
||||
<a href ng-click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
|
||||
</h1>
|
||||
{{item.object.content | html}}
|
||||
<div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
|
||||
<img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
||||
<a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
* # Creating a custom 'PUT' request
|
||||
* In this example we create a custom method on our resource to make a PUT request
|
||||
* <pre>
|
||||
* var app = angular.module('app', ['ngResource', 'ngRoute']);
|
||||
*
|
||||
* // Some APIs expect a PUT request in the format URL/object/ID
|
||||
* // Here we are creating an 'update' method
|
||||
* app.factory('Notes', ['$resource', function($resource) {
|
||||
* return $resource('/notes/:id', null,
|
||||
* {
|
||||
* 'update': { method:'PUT' }
|
||||
* });
|
||||
* }]);
|
||||
*
|
||||
* // In our controller we get the ID from the URL using ngRoute and $routeParams
|
||||
* // We pass in $routeParams and our Notes factory along with $scope
|
||||
* app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
|
||||
function($scope, $routeParams, Notes) {
|
||||
* // First get a note object from the factory
|
||||
* var note = Notes.get({ id:$routeParams.id });
|
||||
* $id = note.id;
|
||||
*
|
||||
* // Now call update passing in the ID first then the object you are updating
|
||||
* Notes.update({ id:$id }, note);
|
||||
*
|
||||
* // This will PUT /notes/ID with the note object in the request payload
|
||||
* }]);
|
||||
* </pre>
|
||||
*/
|
||||
angular.module('ngResource', ['ng']).
|
||||
factory('$resource', ['$http', '$parse', function($http, $parse) {
|
||||
factory('$resource', ['$http', '$q', function($http, $q) {
|
||||
|
||||
var DEFAULT_ACTIONS = {
|
||||
'get': {method:'GET'},
|
||||
'save': {method:'POST'},
|
||||
@@ -238,10 +321,7 @@ angular.module('ngResource', ['ng']).
|
||||
forEach = angular.forEach,
|
||||
extend = angular.extend,
|
||||
copy = angular.copy,
|
||||
isFunction = angular.isFunction,
|
||||
getter = function(obj, path) {
|
||||
return $parse(path)(obj);
|
||||
};
|
||||
isFunction = angular.isFunction;
|
||||
|
||||
/**
|
||||
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
|
||||
@@ -263,9 +343,9 @@ angular.module('ngResource', ['ng']).
|
||||
|
||||
|
||||
/**
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
||||
* method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
|
||||
* encoded per http://tools.ietf.org/html/rfc3986:
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a
|
||||
* custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
|
||||
* have to be encoded per http://tools.ietf.org/html/rfc3986:
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
@@ -283,32 +363,40 @@ angular.module('ngResource', ['ng']).
|
||||
}
|
||||
|
||||
function Route(template, defaults) {
|
||||
this.template = template = template + '#';
|
||||
this.template = template;
|
||||
this.defaults = defaults || {};
|
||||
var urlParams = this.urlParams = {};
|
||||
forEach(template.split(/\W/), function(param){
|
||||
if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
|
||||
urlParams[param] = true;
|
||||
}
|
||||
});
|
||||
this.template = template.replace(/\\:/g, ':');
|
||||
this.urlParams = {};
|
||||
}
|
||||
|
||||
Route.prototype = {
|
||||
url: function(params) {
|
||||
setUrlParams: function(config, params, actionUrl) {
|
||||
var self = this,
|
||||
url = this.template,
|
||||
url = actionUrl || self.template,
|
||||
val,
|
||||
encodedVal;
|
||||
|
||||
var urlParams = self.urlParams = {};
|
||||
forEach(url.split(/\W/), function(param){
|
||||
if (param === 'hasOwnProperty') {
|
||||
throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
|
||||
}
|
||||
if (!(new RegExp("^\\d+$").test(param)) && param &&
|
||||
(new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
|
||||
urlParams[param] = true;
|
||||
}
|
||||
});
|
||||
url = url.replace(/\\:/g, ':');
|
||||
|
||||
params = params || {};
|
||||
forEach(this.urlParams, function(_, urlParam){
|
||||
forEach(self.urlParams, function(_, urlParam){
|
||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
||||
if (angular.isDefined(val) && val !== null) {
|
||||
encodedVal = encodeUriSegment(val);
|
||||
url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
|
||||
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
|
||||
return encodedVal + p1;
|
||||
});
|
||||
} else {
|
||||
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
|
||||
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
|
||||
leadingSlashes, tail) {
|
||||
if (tail.charAt(0) == '/') {
|
||||
return tail;
|
||||
@@ -318,21 +406,28 @@ angular.module('ngResource', ['ng']).
|
||||
});
|
||||
}
|
||||
});
|
||||
url = url.replace(/\/?#$/, '');
|
||||
var query = [];
|
||||
|
||||
// strip trailing slashes and set the url
|
||||
url = url.replace(/\/+$/, '') || '/';
|
||||
// then replace collapse `/.` if found in the last URL path segment before the query
|
||||
// E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
|
||||
url = url.replace(/\/\.(?=\w+($|\?))/, '.');
|
||||
// replace escaped `/\.` with `/.`
|
||||
config.url = url.replace(/\/\\\./, '/.');
|
||||
|
||||
|
||||
// set params - delegate param encoding to $http
|
||||
forEach(params, function(value, key){
|
||||
if (!self.urlParams[key]) {
|
||||
query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value));
|
||||
config.params = config.params || {};
|
||||
config.params[key] = value;
|
||||
}
|
||||
});
|
||||
query.sort();
|
||||
url = url.replace(/\/*$/, '');
|
||||
return url + (query.length ? '?' + query.join('&') : '');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function ResourceFactory(url, paramDefaults, actions) {
|
||||
function resourceFactory(url, paramDefaults, actions) {
|
||||
var route = new Route(url);
|
||||
|
||||
actions = extend({}, DEFAULT_ACTIONS, actions);
|
||||
@@ -341,23 +436,28 @@ angular.module('ngResource', ['ng']).
|
||||
var ids = {};
|
||||
actionParams = extend({}, paramDefaults, actionParams);
|
||||
forEach(actionParams, function(value, key){
|
||||
ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
|
||||
if (isFunction(value)) { value = value(); }
|
||||
ids[key] = value && value.charAt && value.charAt(0) == '@' ?
|
||||
lookupDottedPath(data, value.substr(1)) : value;
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
|
||||
function defaultResponseInterceptor(response) {
|
||||
return response.resource;
|
||||
}
|
||||
|
||||
function Resource(value){
|
||||
copy(value || {}, this);
|
||||
shallowClearAndCopy(value || {}, this);
|
||||
}
|
||||
|
||||
forEach(actions, function(action, name) {
|
||||
action.method = angular.uppercase(action.method);
|
||||
var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
|
||||
var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
|
||||
|
||||
Resource[name] = function(a1, a2, a3, a4) {
|
||||
var params = {};
|
||||
var data;
|
||||
var success = noop;
|
||||
var error = null;
|
||||
var params = {}, data, success, error;
|
||||
|
||||
/* jshint -W086 */ /* (purposefully fall through case statements) */
|
||||
switch(arguments.length) {
|
||||
case 4:
|
||||
error = a4;
|
||||
@@ -388,69 +488,108 @@ angular.module('ngResource', ['ng']).
|
||||
break;
|
||||
case 0: break;
|
||||
default:
|
||||
throw "Expected between 0-4 arguments [params, data, success, error], got " +
|
||||
arguments.length + " arguments.";
|
||||
throw $resourceMinErr('badargs',
|
||||
"Expected up to 4 arguments [params, data, success, error], got {0} arguments",
|
||||
arguments.length);
|
||||
}
|
||||
/* jshint +W086 */ /* (purposefully fall through case statements) */
|
||||
|
||||
var isInstanceCall = this instanceof Resource;
|
||||
var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
|
||||
var httpConfig = {};
|
||||
var responseInterceptor = action.interceptor && action.interceptor.response ||
|
||||
defaultResponseInterceptor;
|
||||
var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
|
||||
undefined;
|
||||
|
||||
forEach(action, function(value, key) {
|
||||
if (key != 'params' && key != 'isArray' && key != 'interceptor') {
|
||||
httpConfig[key] = copy(value);
|
||||
}
|
||||
});
|
||||
|
||||
if (hasBody) httpConfig.data = data;
|
||||
route.setUrlParams(httpConfig,
|
||||
extend({}, extractParams(data, action.params || {}), params),
|
||||
action.url);
|
||||
|
||||
var promise = $http(httpConfig).then(function(response) {
|
||||
var data = response.data,
|
||||
promise = value.$promise;
|
||||
|
||||
if (data) {
|
||||
// Need to convert action.isArray to boolean in case it is undefined
|
||||
// jshint -W018
|
||||
if (angular.isArray(data) !== (!!action.isArray)) {
|
||||
throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
|
||||
'response to contain an {0} but got an {1}',
|
||||
action.isArray?'array':'object', angular.isArray(data)?'array':'object');
|
||||
}
|
||||
// jshint +W018
|
||||
if (action.isArray) {
|
||||
value.length = 0;
|
||||
forEach(data, function(item) {
|
||||
value.push(new Resource(item));
|
||||
});
|
||||
} else {
|
||||
shallowClearAndCopy(data, value);
|
||||
value.$promise = promise;
|
||||
}
|
||||
}
|
||||
|
||||
value.$resolved = true;
|
||||
|
||||
response.resource = value;
|
||||
|
||||
return response;
|
||||
}, function(response) {
|
||||
value.$resolved = true;
|
||||
|
||||
(error||noop)(response);
|
||||
|
||||
return $q.reject(response);
|
||||
});
|
||||
|
||||
promise = promise.then(
|
||||
function(response) {
|
||||
var value = responseInterceptor(response);
|
||||
(success||noop)(value, response.headers);
|
||||
return value;
|
||||
},
|
||||
responseErrorInterceptor);
|
||||
|
||||
if (!isInstanceCall) {
|
||||
// we are creating instance / collection
|
||||
// - set the initial promise
|
||||
// - return the instance / collection
|
||||
value.$promise = promise;
|
||||
value.$resolved = false;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
|
||||
$http({
|
||||
method: action.method,
|
||||
url: route.url(extend({}, extractParams(data, action.params || {}), params)),
|
||||
data: data
|
||||
}).then(function(response) {
|
||||
var data = response.data;
|
||||
|
||||
if (data) {
|
||||
if (action.isArray) {
|
||||
value.length = 0;
|
||||
forEach(data, function(item) {
|
||||
value.push(new Resource(item));
|
||||
});
|
||||
} else {
|
||||
copy(data, value);
|
||||
}
|
||||
}
|
||||
(success||noop)(value, response.headers);
|
||||
}, error);
|
||||
|
||||
return value;
|
||||
// instance call
|
||||
return promise;
|
||||
};
|
||||
|
||||
|
||||
Resource.prototype['$' + name] = function(a1, a2, a3) {
|
||||
var params = extractParams(this),
|
||||
success = noop,
|
||||
error;
|
||||
|
||||
switch(arguments.length) {
|
||||
case 3: params = a1; success = a2; error = a3; break;
|
||||
case 2:
|
||||
case 1:
|
||||
if (isFunction(a1)) {
|
||||
success = a1;
|
||||
error = a2;
|
||||
} else {
|
||||
params = a1;
|
||||
success = a2 || noop;
|
||||
}
|
||||
case 0: break;
|
||||
default:
|
||||
throw "Expected between 1-3 arguments [params, success, error], got " +
|
||||
arguments.length + " arguments.";
|
||||
Resource.prototype['$' + name] = function(params, success, error) {
|
||||
if (isFunction(params)) {
|
||||
error = success; success = params; params = {};
|
||||
}
|
||||
var data = hasBody ? this : undefined;
|
||||
Resource[name].call(this, params, data, success, error);
|
||||
var result = Resource[name].call(this, params, this, success, error);
|
||||
return result.$promise || result;
|
||||
};
|
||||
});
|
||||
|
||||
Resource.bind = function(additionalParamDefaults){
|
||||
return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
|
||||
return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
|
||||
};
|
||||
|
||||
return Resource;
|
||||
}
|
||||
|
||||
return ResourceFactory;
|
||||
return resourceFactory;
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
+921
@@ -0,0 +1,921 @@
|
||||
/**
|
||||
* @license AngularJS v1.2.13
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name ngRoute
|
||||
* @description
|
||||
*
|
||||
* # ngRoute
|
||||
*
|
||||
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* {@installModule route}
|
||||
*
|
||||
* <div doc-module-components="ngRoute"></div>
|
||||
*/
|
||||
/* global -ngRouteModule */
|
||||
var ngRouteModule = angular.module('ngRoute', ['ng']).
|
||||
provider('$route', $RouteProvider);
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$routeProvider
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Used for configuring routes.
|
||||
*
|
||||
* ## Example
|
||||
* See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
|
||||
*
|
||||
* ## Dependencies
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*/
|
||||
function $RouteProvider(){
|
||||
function inherit(parent, extra) {
|
||||
return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
|
||||
}
|
||||
|
||||
var routes = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$routeProvider#when
|
||||
* @methodOf ngRoute.$routeProvider
|
||||
*
|
||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||
* route definition.
|
||||
*
|
||||
* * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
|
||||
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain named groups starting with a colon and ending with a star:
|
||||
* e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
|
||||
* when the route matches.
|
||||
* * `path` can contain optional named groups with a question mark: e.g.`:name?`.
|
||||
*
|
||||
* For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
|
||||
* `/color/brown/largecode/code/with/slashs/edit` and extract:
|
||||
*
|
||||
* * `color: brown`
|
||||
* * `largecode: code/with/slashs`.
|
||||
*
|
||||
*
|
||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||
* match.
|
||||
*
|
||||
* Object properties:
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with
|
||||
* newly created scope or the name of a {@link angular.Module#controller registered
|
||||
* controller} if passed as a string.
|
||||
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
||||
* published to scope under the `controllerAs` name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used by {@link
|
||||
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
||||
* This property takes precedence over `templateUrl`.
|
||||
*
|
||||
* If `template` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
||||
*
|
||||
* If `templateUrl` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Array.<Object>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route
|
||||
*
|
||||
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||
* be injected into the controller. If any of these dependencies are promises, the router
|
||||
* will wait for them all to be resolved or one to be rejected before the controller is
|
||||
* instantiated.
|
||||
* If all the promises are resolved successfully, the values of the resolved promises are
|
||||
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
|
||||
* fired. If any of the promises are rejected the
|
||||
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
|
||||
* is:
|
||||
*
|
||||
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
|
||||
* and the return value is treated as the dependency. If the result is a promise, it is
|
||||
* resolved before its value is injected into the controller. Be aware that
|
||||
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
|
||||
* functions. Use `$route.current.params` to access the new route parameters, instead.
|
||||
*
|
||||
* - `redirectTo` – {(string|function())=} – value to update
|
||||
* {@link ng.$location $location} path with and trigger route redirection.
|
||||
*
|
||||
* If `redirectTo` is a function, it will be called with the following parameters:
|
||||
*
|
||||
* - `{Object.<string>}` - route parameters extracted from the current
|
||||
* `$location.path()` by applying the current route templateUrl.
|
||||
* - `{string}` - current `$location.path()`
|
||||
* - `{Object}` - current `$location.search()`
|
||||
*
|
||||
* The custom `redirectTo` function is expected to return a string which will be used
|
||||
* to update `$location.path()` and `$location.search()`.
|
||||
*
|
||||
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
|
||||
* or `$location.hash()` changes.
|
||||
*
|
||||
* If the option is set to `false` and url in the browser changes, then
|
||||
* `$routeUpdate` event is broadcasted on the root scope.
|
||||
*
|
||||
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
||||
*
|
||||
* If the option is set to `true`, then the particular route can be matched without being
|
||||
* case sensitive
|
||||
*
|
||||
* @returns {Object} self
|
||||
*
|
||||
* @description
|
||||
* Adds a new route definition to the `$route` service.
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
routes[path] = angular.extend(
|
||||
{reloadOnSearch: true},
|
||||
route,
|
||||
path && pathRegExp(path, route)
|
||||
);
|
||||
|
||||
// create redirection for trailing slashes
|
||||
if (path) {
|
||||
var redirectPath = (path[path.length-1] == '/')
|
||||
? path.substr(0, path.length-1)
|
||||
: path +'/';
|
||||
|
||||
routes[redirectPath] = angular.extend(
|
||||
{redirectTo: path},
|
||||
pathRegExp(redirectPath, route)
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param path {string} path
|
||||
* @param opts {Object} options
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Normalizes the given path, returning a regular expression
|
||||
* and the original path.
|
||||
*
|
||||
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
||||
*/
|
||||
function pathRegExp(path, opts) {
|
||||
var insensitive = opts.caseInsensitiveMatch,
|
||||
ret = {
|
||||
originalPath: path,
|
||||
regexp: path
|
||||
},
|
||||
keys = ret.keys = [];
|
||||
|
||||
path = path
|
||||
.replace(/([().])/g, '\\$1')
|
||||
.replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
|
||||
var optional = option === '?' ? option : null;
|
||||
var star = option === '*' ? option : null;
|
||||
keys.push({ name: key, optional: !!optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (star && '(.+?)' || '([^/]+)')
|
||||
+ (optional || '')
|
||||
+ ')'
|
||||
+ (optional || '');
|
||||
})
|
||||
.replace(/([\/$\*])/g, '\\$1');
|
||||
|
||||
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$routeProvider#otherwise
|
||||
* @methodOf ngRoute.$routeProvider
|
||||
*
|
||||
* @description
|
||||
* Sets route definition that will be used on route change when no other route definition
|
||||
* is matched.
|
||||
*
|
||||
* @param {Object} params Mapping information to be assigned to `$route.current`.
|
||||
* @returns {Object} self
|
||||
*/
|
||||
this.otherwise = function(params) {
|
||||
this.when(null, params);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$rootScope',
|
||||
'$location',
|
||||
'$routeParams',
|
||||
'$q',
|
||||
'$injector',
|
||||
'$http',
|
||||
'$templateCache',
|
||||
'$sce',
|
||||
function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$route
|
||||
* @requires $location
|
||||
* @requires $routeParams
|
||||
*
|
||||
* @property {Object} current Reference to the current route definition.
|
||||
* The route definition contains:
|
||||
*
|
||||
* - `controller`: The controller constructor as define in route definition.
|
||||
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
||||
* controller instantiation. The `locals` contain
|
||||
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
||||
*
|
||||
* - `$scope` - The current route scope.
|
||||
* - `$template` - The current route template HTML.
|
||||
*
|
||||
* @property {Array.<Object>} routes Array of all configured routes.
|
||||
*
|
||||
* @description
|
||||
* `$route` is used for deep-linking URLs to controllers and views (HTML partials).
|
||||
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
|
||||
*
|
||||
* The `$route` service is typically used in conjunction with the
|
||||
* {@link ngRoute.directive:ngView `ngView`} directive and the
|
||||
* {@link ngRoute.$routeParams `$routeParams`} service.
|
||||
*
|
||||
* @example
|
||||
This example shows how changing the URL hash causes the `$route` to match a route against the
|
||||
URL, and the `ngView` pulls in the partial.
|
||||
|
||||
Note that this example is using {@link ng.directive:script inlined templates}
|
||||
to get it working on jsfiddle as well.
|
||||
|
||||
<example module="ngViewExample" deps="angular-route.js">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCntl">
|
||||
Choose:
|
||||
<a href="Book/Moby">Moby</a> |
|
||||
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
<a href="Book/Gatsby">Gatsby</a> |
|
||||
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
|
||||
<div ng-view></div>
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{$location.path()}}</pre>
|
||||
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{$routeParams}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="book.html">
|
||||
controller: {{name}}<br />
|
||||
Book Id: {{params.bookId}}<br />
|
||||
</file>
|
||||
|
||||
<file name="chapter.html">
|
||||
controller: {{name}}<br />
|
||||
Book Id: {{params.bookId}}<br />
|
||||
Chapter Id: {{params.chapterId}}
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('ngViewExample', ['ngRoute'])
|
||||
|
||||
.config(function($routeProvider, $locationProvider) {
|
||||
$routeProvider.when('/Book/:bookId', {
|
||||
templateUrl: 'book.html',
|
||||
controller: BookCntl,
|
||||
resolve: {
|
||||
// I will cause a 1 second delay
|
||||
delay: function($q, $timeout) {
|
||||
var delay = $q.defer();
|
||||
$timeout(delay.resolve, 1000);
|
||||
return delay.promise;
|
||||
}
|
||||
}
|
||||
});
|
||||
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
||||
templateUrl: 'chapter.html',
|
||||
controller: ChapterCntl
|
||||
});
|
||||
|
||||
// configure html5 to get links working on jsfiddle
|
||||
$locationProvider.html5Mode(true);
|
||||
});
|
||||
|
||||
function MainCntl($scope, $route, $routeParams, $location) {
|
||||
$scope.$route = $route;
|
||||
$scope.$location = $location;
|
||||
$scope.$routeParams = $routeParams;
|
||||
}
|
||||
|
||||
function BookCntl($scope, $routeParams) {
|
||||
$scope.name = "BookCntl";
|
||||
$scope.params = $routeParams;
|
||||
}
|
||||
|
||||
function ChapterCntl($scope, $routeParams) {
|
||||
$scope.name = "ChapterCntl";
|
||||
$scope.params = $routeParams;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="protractorTest.js">
|
||||
it('should load and compile correct template', function() {
|
||||
element(by.linkText('Moby: Ch1')).click();
|
||||
var content = element(by.css('.doc-example-live [ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: ChapterCntl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
|
||||
element(by.partialLinkText('Scarlet')).click();
|
||||
|
||||
content = element(by.css('.doc-example-live [ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: BookCntl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeStart
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted before a route change. At this point the route services starts
|
||||
* resolving all of the dependencies needed for the route change to occur.
|
||||
* Typically this involves fetching the view template as well as any dependencies
|
||||
* defined in `resolve` route property. Once all of the dependencies are resolved
|
||||
* `$routeChangeSuccess` is fired.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} next Future route information.
|
||||
* @param {Route} current Current route information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeSuccess
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted after a route dependencies are resolved.
|
||||
* {@link ngRoute.directive:ngView ngView} listens for the directive
|
||||
* to instantiate the controller and render the view.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route|Undefined} previous Previous route information, or undefined if current is
|
||||
* first route entered.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeChangeError
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
* Broadcasted if any of the resolve promises are rejected.
|
||||
*
|
||||
* @param {Object} angularEvent Synthetic event object
|
||||
* @param {Route} current Current route information.
|
||||
* @param {Route} previous Previous route information.
|
||||
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.$route#$routeUpdate
|
||||
* @eventOf ngRoute.$route
|
||||
* @eventType broadcast on root scope
|
||||
* @description
|
||||
*
|
||||
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
||||
* instance of the Controller.
|
||||
*/
|
||||
|
||||
var forceReload = false,
|
||||
$route = {
|
||||
routes: routes,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ngRoute.$route#reload
|
||||
* @methodOf ngRoute.$route
|
||||
*
|
||||
* @description
|
||||
* Causes `$route` service to reload the current route even if
|
||||
* {@link ng.$location $location} hasn't changed.
|
||||
*
|
||||
* As a result of that, {@link ngRoute.directive:ngView ngView}
|
||||
* creates new scope, reinstantiates the controller.
|
||||
*/
|
||||
reload: function() {
|
||||
forceReload = true;
|
||||
$rootScope.$evalAsync(updateRoute);
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.$on('$locationChangeSuccess', updateRoute);
|
||||
|
||||
return $route;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param on {string} current url
|
||||
* @param route {Object} route regexp to match the url against
|
||||
* @return {?Object}
|
||||
*
|
||||
* @description
|
||||
* Check if the route matches the current url.
|
||||
*
|
||||
* Inspired by match in
|
||||
* visionmedia/express/lib/router/router.js.
|
||||
*/
|
||||
function switchRouteMatcher(on, route) {
|
||||
var keys = route.keys,
|
||||
params = {};
|
||||
|
||||
if (!route.regexp) return null;
|
||||
|
||||
var m = route.regexp.exec(on);
|
||||
if (!m) return null;
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
|
||||
if (key && val) {
|
||||
params[key.name] = val;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
function updateRoute() {
|
||||
var next = parseRoute(),
|
||||
last = $route.current;
|
||||
|
||||
if (next && last && next.$$route === last.$$route
|
||||
&& angular.equals(next.pathParams, last.pathParams)
|
||||
&& !next.reloadOnSearch && !forceReload) {
|
||||
last.params = next.params;
|
||||
angular.copy(last.params, $routeParams);
|
||||
$rootScope.$broadcast('$routeUpdate', last);
|
||||
} else if (next || last) {
|
||||
forceReload = false;
|
||||
$rootScope.$broadcast('$routeChangeStart', next, last);
|
||||
$route.current = next;
|
||||
if (next) {
|
||||
if (next.redirectTo) {
|
||||
if (angular.isString(next.redirectTo)) {
|
||||
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
||||
.replace();
|
||||
} else {
|
||||
$location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
|
||||
.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$q.when(next).
|
||||
then(function() {
|
||||
if (next) {
|
||||
var locals = angular.extend({}, next.resolve),
|
||||
template, templateUrl;
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value);
|
||||
});
|
||||
|
||||
if (angular.isDefined(template = next.template)) {
|
||||
if (angular.isFunction(template)) {
|
||||
template = template(next.params);
|
||||
}
|
||||
} else if (angular.isDefined(templateUrl = next.templateUrl)) {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(next.params);
|
||||
}
|
||||
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
next.loadedTemplateUrl = templateUrl;
|
||||
template = $http.get(templateUrl, {cache: $templateCache}).
|
||||
then(function(response) { return response.data; });
|
||||
}
|
||||
}
|
||||
if (angular.isDefined(template)) {
|
||||
locals['$template'] = template;
|
||||
}
|
||||
return $q.all(locals);
|
||||
}
|
||||
}).
|
||||
// after route change
|
||||
then(function(locals) {
|
||||
if (next == $route.current) {
|
||||
if (next) {
|
||||
next.locals = locals;
|
||||
angular.copy(next.params, $routeParams);
|
||||
}
|
||||
$rootScope.$broadcast('$routeChangeSuccess', next, last);
|
||||
}
|
||||
}, function(error) {
|
||||
if (next == $route.current) {
|
||||
$rootScope.$broadcast('$routeChangeError', next, last, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns the current active route, by matching it against the URL
|
||||
*/
|
||||
function parseRoute() {
|
||||
// Match a route
|
||||
var params, match;
|
||||
angular.forEach(routes, function(route, path) {
|
||||
if (!match && (params = switchRouteMatcher($location.path(), route))) {
|
||||
match = inherit(route, {
|
||||
params: angular.extend({}, $location.search(), params),
|
||||
pathParams: params});
|
||||
match.$$route = route;
|
||||
}
|
||||
});
|
||||
// No route matched; fallback to "otherwise" route
|
||||
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns interpolation of the redirect path with the parameters
|
||||
*/
|
||||
function interpolate(string, params) {
|
||||
var result = [];
|
||||
angular.forEach((string||'').split(':'), function(segment, i) {
|
||||
if (i === 0) {
|
||||
result.push(segment);
|
||||
} else {
|
||||
var segmentMatch = segment.match(/(\w+)(.*)/);
|
||||
var key = segmentMatch[1];
|
||||
result.push(params[key]);
|
||||
result.push(segmentMatch[2] || '');
|
||||
delete params[key];
|
||||
}
|
||||
});
|
||||
return result.join('');
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc object
|
||||
* @name ngRoute.$routeParams
|
||||
* @requires $route
|
||||
*
|
||||
* @description
|
||||
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* The route parameters are a combination of {@link ng.$location `$location`}'s
|
||||
* {@link ng.$location#methods_search `search()`} and {@link ng.$location#methods_path `path()`}.
|
||||
* The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
|
||||
*
|
||||
* In case of parameter name collision, `path` params take precedence over `search` params.
|
||||
*
|
||||
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
|
||||
* (but its properties will likely change) even when a route change occurs.
|
||||
*
|
||||
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
|
||||
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
|
||||
* Instead you can use `$route.current.params` to access the new route's parameters.
|
||||
*
|
||||
* @example
|
||||
* <pre>
|
||||
* // Given:
|
||||
* // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
|
||||
* // Route: /Chapter/:chapterId/Section/:sectionId
|
||||
* //
|
||||
* // Then
|
||||
* $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
|
||||
* </pre>
|
||||
*/
|
||||
function $RouteParamsProvider() {
|
||||
this.$get = function() { return {}; };
|
||||
}
|
||||
|
||||
ngRouteModule.directive('ngView', ngViewFactory);
|
||||
ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngRoute.directive:ngView
|
||||
* @restrict ECA
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
||||
* including the rendered template of the current route into the main layout (`index.html`) file.
|
||||
* Every time the current route changes, the included view changes with it according to the
|
||||
* configuration of the `$route` service.
|
||||
*
|
||||
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
||||
*
|
||||
* @animations
|
||||
* enter - animation is used to bring new content into the browser.
|
||||
* leave - animation is used to animate existing content away.
|
||||
*
|
||||
* The enter and leave animation occur concurrently.
|
||||
*
|
||||
* @scope
|
||||
* @priority 400
|
||||
* @param {string=} onload Expression to evaluate whenever the view updates.
|
||||
*
|
||||
* @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
|
||||
* $anchorScroll} to scroll the viewport after the view is updated.
|
||||
*
|
||||
* - If the attribute is not set, disable scrolling.
|
||||
* - If the attribute is set without value, enable scrolling.
|
||||
* - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
|
||||
* as an expression yields a truthy value.
|
||||
* @example
|
||||
<example module="ngViewExample" deps="angular-route.js" animations="true">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MainCntl as main">
|
||||
Choose:
|
||||
<a href="Book/Moby">Moby</a> |
|
||||
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
||||
<a href="Book/Gatsby">Gatsby</a> |
|
||||
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
||||
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
||||
|
||||
<div class="view-animate-container">
|
||||
<div ng-view class="view-animate"></div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{main.$location.path()}}</pre>
|
||||
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{main.$routeParams}}</pre>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="book.html">
|
||||
<div>
|
||||
controller: {{book.name}}<br />
|
||||
Book Id: {{book.params.bookId}}<br />
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="chapter.html">
|
||||
<div>
|
||||
controller: {{chapter.name}}<br />
|
||||
Book Id: {{chapter.params.bookId}}<br />
|
||||
Chapter Id: {{chapter.params.chapterId}}
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="animations.css">
|
||||
.view-animate-container {
|
||||
position:relative;
|
||||
height:100px!important;
|
||||
position:relative;
|
||||
background:white;
|
||||
border:1px solid black;
|
||||
height:40px;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.view-animate {
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter, .view-animate.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
||||
|
||||
display:block;
|
||||
width:100%;
|
||||
border-left:1px solid black;
|
||||
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
right:0;
|
||||
bottom:0;
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
.view-animate.ng-enter {
|
||||
left:100%;
|
||||
}
|
||||
.view-animate.ng-enter.ng-enter-active {
|
||||
left:0;
|
||||
}
|
||||
.view-animate.ng-leave.ng-leave-active {
|
||||
left:-100%;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('ngViewExample', ['ngRoute', 'ngAnimate'],
|
||||
function($routeProvider, $locationProvider) {
|
||||
$routeProvider.when('/Book/:bookId', {
|
||||
templateUrl: 'book.html',
|
||||
controller: BookCntl,
|
||||
controllerAs: 'book'
|
||||
});
|
||||
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
||||
templateUrl: 'chapter.html',
|
||||
controller: ChapterCntl,
|
||||
controllerAs: 'chapter'
|
||||
});
|
||||
|
||||
// configure html5 to get links working on jsfiddle
|
||||
$locationProvider.html5Mode(true);
|
||||
});
|
||||
|
||||
function MainCntl($route, $routeParams, $location) {
|
||||
this.$route = $route;
|
||||
this.$location = $location;
|
||||
this.$routeParams = $routeParams;
|
||||
}
|
||||
|
||||
function BookCntl($routeParams) {
|
||||
this.name = "BookCntl";
|
||||
this.params = $routeParams;
|
||||
}
|
||||
|
||||
function ChapterCntl($routeParams) {
|
||||
this.name = "ChapterCntl";
|
||||
this.params = $routeParams;
|
||||
}
|
||||
</file>
|
||||
|
||||
<file name="protractorTest.js">
|
||||
it('should load and compile correct template', function() {
|
||||
element(by.linkText('Moby: Ch1')).click();
|
||||
var content = element(by.css('.doc-example-live [ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: ChapterCntl/);
|
||||
expect(content).toMatch(/Book Id\: Moby/);
|
||||
expect(content).toMatch(/Chapter Id\: 1/);
|
||||
|
||||
element(by.partialLinkText('Scarlet')).click();
|
||||
|
||||
content = element(by.css('.doc-example-live [ng-view]')).getText();
|
||||
expect(content).toMatch(/controller\: BookCntl/);
|
||||
expect(content).toMatch(/Book Id\: Scarlet/);
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc event
|
||||
* @name ngRoute.directive:ngView#$viewContentLoaded
|
||||
* @eventOf ngRoute.directive:ngView
|
||||
* @eventType emit on the current ngView scope
|
||||
* @description
|
||||
* Emitted every time the ngView content is reloaded.
|
||||
*/
|
||||
ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
|
||||
function ngViewFactory( $route, $anchorScroll, $animate) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
transclude: 'element',
|
||||
link: function(scope, $element, attr, ctrl, $transclude) {
|
||||
var currentScope,
|
||||
currentElement,
|
||||
autoScrollExp = attr.autoscroll,
|
||||
onloadExp = attr.onload || '';
|
||||
|
||||
scope.$on('$routeChangeSuccess', update);
|
||||
update();
|
||||
|
||||
function cleanupLastView() {
|
||||
if (currentScope) {
|
||||
currentScope.$destroy();
|
||||
currentScope = null;
|
||||
}
|
||||
if(currentElement) {
|
||||
$animate.leave(currentElement);
|
||||
currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var locals = $route.current && $route.current.locals,
|
||||
template = locals && locals.$template;
|
||||
|
||||
if (angular.isDefined(template)) {
|
||||
var newScope = scope.$new();
|
||||
var current = $route.current;
|
||||
|
||||
// Note: This will also link all children of ng-view that were contained in the original
|
||||
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||
// However, using ng-view on an element with additional content does not make sense...
|
||||
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
$animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
|
||||
if (angular.isDefined(autoScrollExp)
|
||||
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
}
|
||||
});
|
||||
cleanupLastView();
|
||||
});
|
||||
|
||||
currentElement = clone;
|
||||
currentScope = current.scope = newScope;
|
||||
currentScope.$emit('$viewContentLoaded');
|
||||
currentScope.$eval(onloadExp);
|
||||
} else {
|
||||
cleanupLastView();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// This directive is called during the $transclude call of the first `ngView` directive.
|
||||
// It will replace and compile the content of the element with the loaded template.
|
||||
// We need this directive so that the element content is already filled when
|
||||
// the link function of another directive on the same element as ngView
|
||||
// is called.
|
||||
ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
|
||||
function ngViewFillContentFactory($compile, $controller, $route) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: -400,
|
||||
link: function(scope, $element) {
|
||||
var current = $route.current,
|
||||
locals = current.locals;
|
||||
|
||||
$element.html(locals.$template);
|
||||
|
||||
var link = $compile($element.contents());
|
||||
|
||||
if (current.controller) {
|
||||
locals.$scope = scope;
|
||||
var controller = $controller(current.controller, locals);
|
||||
if (current.controllerAs) {
|
||||
scope[current.controllerAs] = controller;
|
||||
}
|
||||
$element.data('$ngControllerController', controller);
|
||||
$element.children().data('$ngControllerController', controller);
|
||||
}
|
||||
|
||||
link(scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
})(window, window.angular);
|
||||
Vendored
Executable → Regular
+249
-161
@@ -1,15 +1,26 @@
|
||||
/**
|
||||
* @license AngularJS v1.0.7
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* @license AngularJS v1.2.13
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
'use strict';
|
||||
(function(window, angular, undefined) {'use strict';
|
||||
|
||||
var $sanitizeMinErr = angular.$$minErr('$sanitize');
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name ngSanitize
|
||||
* @description
|
||||
*
|
||||
* # ngSanitize
|
||||
*
|
||||
* The `ngSanitize` module provides functionality to sanitize HTML.
|
||||
*
|
||||
* {@installModule sanitize}
|
||||
*
|
||||
* <div doc-module-components="ngSanitize"></div>
|
||||
*
|
||||
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -40,97 +51,124 @@
|
||||
* it into the returned string, however, since our parser is more strict than a typical browser
|
||||
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
|
||||
* browser, won't make it through the sanitizer.
|
||||
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
|
||||
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
|
||||
*
|
||||
* @param {string} html Html input.
|
||||
* @returns {string} Sanitized html.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="ngSanitize">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl($scope) {
|
||||
$scope.snippet =
|
||||
'<p style="color:blue">an html\n' +
|
||||
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
||||
'snippet</p>';
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl">
|
||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Filter</td>
|
||||
<td>Source</td>
|
||||
<td>Rendered</td>
|
||||
</tr>
|
||||
<tr id="html-filter">
|
||||
<td>html filter</td>
|
||||
<td>
|
||||
<pre><div ng-bind-html="snippet"><br/></div></pre>
|
||||
</td>
|
||||
<td>
|
||||
<div ng-bind-html="snippet"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="escaped-html">
|
||||
<td>no filter</td>
|
||||
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
||||
<td><div ng-bind="snippet"></div></td>
|
||||
</tr>
|
||||
<tr id="html-unsafe-filter">
|
||||
<td>unsafe html filter</td>
|
||||
<td><pre><div ng-bind-html-unsafe="snippet"><br/></div></pre></td>
|
||||
<td><div ng-bind-html-unsafe="snippet"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should sanitize the html snippet ', function() {
|
||||
expect(using('#html-filter').element('div').html()).
|
||||
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
||||
});
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl($scope, $sce) {
|
||||
$scope.snippet =
|
||||
'<p style="color:blue">an html\n' +
|
||||
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
||||
'snippet</p>';
|
||||
$scope.deliberatelyTrustDangerousSnippet = function() {
|
||||
return $sce.trustAsHtml($scope.snippet);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl">
|
||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Directive</td>
|
||||
<td>How</td>
|
||||
<td>Source</td>
|
||||
<td>Rendered</td>
|
||||
</tr>
|
||||
<tr id="bind-html-with-sanitize">
|
||||
<td>ng-bind-html</td>
|
||||
<td>Automatically uses $sanitize</td>
|
||||
<td><pre><div ng-bind-html="snippet"><br/></div></pre></td>
|
||||
<td><div ng-bind-html="snippet"></div></td>
|
||||
</tr>
|
||||
<tr id="bind-html-with-trust">
|
||||
<td>ng-bind-html</td>
|
||||
<td>Bypass $sanitize by explicitly trusting the dangerous value</td>
|
||||
<td>
|
||||
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
|
||||
</div></pre>
|
||||
</td>
|
||||
<td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
|
||||
</tr>
|
||||
<tr id="bind-default">
|
||||
<td>ng-bind</td>
|
||||
<td>Automatically escapes</td>
|
||||
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
||||
<td><div ng-bind="snippet"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:protractor>
|
||||
it('should sanitize the html snippet by default', function() {
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
||||
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
||||
});
|
||||
|
||||
it('should escape snippet without any filter', function() {
|
||||
expect(using('#escaped-html').element('div').html()).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
});
|
||||
it('should inline raw snippet if bound to a trusted value', function() {
|
||||
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
});
|
||||
|
||||
it('should inline raw snippet if filtered as unsafe', function() {
|
||||
expect(using('#html-unsafe-filter').element("div").html()).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
});
|
||||
it('should escape snippet without any filter', function() {
|
||||
expect(element(by.css('#bind-default div')).getInnerHtml()).
|
||||
toBe("<p style=\"color:blue\">an html\n" +
|
||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
||||
"snippet</p>");
|
||||
});
|
||||
|
||||
it('should update', function() {
|
||||
input('snippet').enter('new <b>text</b>');
|
||||
expect(using('#html-filter').binding('snippet')).toBe('new <b>text</b>');
|
||||
expect(using('#escaped-html').element('div').html()).toBe("new <b>text</b>");
|
||||
expect(using('#html-unsafe-filter').binding("snippet")).toBe('new <b>text</b>');
|
||||
});
|
||||
</doc:scenario>
|
||||
it('should update', function() {
|
||||
element(by.model('snippet')).clear();
|
||||
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
|
||||
expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
|
||||
toBe('new <b>text</b>');
|
||||
expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
|
||||
'new <b onclick="alert(1)">text</b>');
|
||||
expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
|
||||
"new <b onclick=\"alert(1)\">text</b>");
|
||||
});
|
||||
</doc:protractor>
|
||||
</doc:example>
|
||||
*/
|
||||
var $sanitize = function(html) {
|
||||
function $SanitizeProvider() {
|
||||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
|
||||
return function(html) {
|
||||
var buf = [];
|
||||
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) {
|
||||
return !/^unsafe/.test($$sanitizeUri(uri, isImage));
|
||||
}));
|
||||
return buf.join('');
|
||||
};
|
||||
}];
|
||||
}
|
||||
|
||||
function sanitizeText(chars) {
|
||||
var buf = [];
|
||||
htmlParser(html, htmlSanitizeWriter(buf));
|
||||
return buf.join('');
|
||||
};
|
||||
var writer = htmlSanitizeWriter(buf, angular.noop);
|
||||
writer.chars(chars);
|
||||
return buf.join('');
|
||||
}
|
||||
|
||||
|
||||
// Regular Expressions for parsing tags and attributes
|
||||
var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
||||
var START_TAG_REGEXP =
|
||||
/^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
||||
END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
|
||||
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
||||
BEGIN_TAG_REGEXP = /^</,
|
||||
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
||||
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
||||
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i,
|
||||
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
||||
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/,
|
||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
|
||||
// Match everything outside of normal chars and " (quote character)
|
||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
|
||||
|
||||
|
||||
// Good source of info about elements and attributes
|
||||
@@ -145,23 +183,29 @@ var voidElements = makeMap("area,br,col,hr,img,wbr");
|
||||
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
||||
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
||||
optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
||||
optionalEndTagElements = angular.extend({},
|
||||
optionalEndTagInlineElements,
|
||||
optionalEndTagBlockElements);
|
||||
|
||||
// Safe Block Elements - HTML5
|
||||
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," +
|
||||
"blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
|
||||
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
||||
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," +
|
||||
"aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
|
||||
"h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
||||
|
||||
// Inline Elements - HTML5
|
||||
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," +
|
||||
"big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
|
||||
"span,strike,strong,sub,sup,time,tt,u,var"));
|
||||
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," +
|
||||
"bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
|
||||
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
|
||||
|
||||
|
||||
// Special Elements (can contain anything)
|
||||
var specialElements = makeMap("script,style");
|
||||
|
||||
var validElements = angular.extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
|
||||
var validElements = angular.extend({},
|
||||
voidElements,
|
||||
blockElements,
|
||||
inlineElements,
|
||||
optionalEndTagElements);
|
||||
|
||||
//Attributes that have href and hence need to be sanitized
|
||||
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
||||
@@ -169,7 +213,7 @@ var validAttrs = angular.extend({}, uriAttrs, makeMap(
|
||||
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
||||
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
||||
'scope,scrolling,shape,size,span,start,summary,target,title,type,'+
|
||||
'valign,value,vspace,width'));
|
||||
|
||||
function makeMap(str) {
|
||||
@@ -203,14 +247,22 @@ function htmlParser( html, handler ) {
|
||||
|
||||
// Comment
|
||||
if ( html.indexOf("<!--") === 0 ) {
|
||||
index = html.indexOf("-->");
|
||||
// comments containing -- are not allowed unless they terminate the comment
|
||||
index = html.indexOf("--", 4);
|
||||
|
||||
if ( index >= 0 ) {
|
||||
if ( index >= 0 && html.lastIndexOf("-->", index) === index) {
|
||||
if (handler.comment) handler.comment( html.substring( 4, index ) );
|
||||
html = html.substring( index + 3 );
|
||||
chars = false;
|
||||
}
|
||||
// DOCTYPE
|
||||
} else if ( DOCTYPE_REGEXP.test(html) ) {
|
||||
match = html.match( DOCTYPE_REGEXP );
|
||||
|
||||
if ( match ) {
|
||||
html = html.replace( match[0] , '');
|
||||
chars = false;
|
||||
}
|
||||
// end tag
|
||||
} else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
|
||||
match = html.match( END_TAG_REGEXP );
|
||||
@@ -242,21 +294,21 @@ function htmlParser( html, handler ) {
|
||||
}
|
||||
|
||||
} else {
|
||||
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), function(all, text){
|
||||
text = text.
|
||||
replace(COMMENT_REGEXP, "$1").
|
||||
replace(CDATA_REGEXP, "$1");
|
||||
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'),
|
||||
function(all, text){
|
||||
text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1");
|
||||
|
||||
if (handler.chars) handler.chars( decodeEntities(text) );
|
||||
if (handler.chars) handler.chars( decodeEntities(text) );
|
||||
|
||||
return "";
|
||||
return "";
|
||||
});
|
||||
|
||||
parseEndTag( "", stack.last() );
|
||||
}
|
||||
|
||||
if ( html == last ) {
|
||||
throw "Parse Error: " + html;
|
||||
throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " +
|
||||
"of html: {0}", html);
|
||||
}
|
||||
last = html;
|
||||
}
|
||||
@@ -283,13 +335,14 @@ function htmlParser( html, handler ) {
|
||||
|
||||
var attrs = {};
|
||||
|
||||
rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) {
|
||||
var value = doubleQuotedValue
|
||||
|| singleQoutedValue
|
||||
|| unqoutedValue
|
||||
|| '';
|
||||
rest.replace(ATTR_REGEXP,
|
||||
function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) {
|
||||
var value = doubleQuotedValue
|
||||
|| singleQuotedValue
|
||||
|| unquotedValue
|
||||
|| '';
|
||||
|
||||
attrs[name] = decodeEntities(value);
|
||||
attrs[name] = decodeEntities(value);
|
||||
});
|
||||
if (handler.start) handler.start( tagName, attrs, unary );
|
||||
}
|
||||
@@ -314,15 +367,32 @@ function htmlParser( html, handler ) {
|
||||
}
|
||||
}
|
||||
|
||||
var hiddenPre=document.createElement("pre");
|
||||
var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
|
||||
/**
|
||||
* decodes all entities into regular string
|
||||
* @param value
|
||||
* @returns {string} A string with decoded entities.
|
||||
*/
|
||||
var hiddenPre=document.createElement("pre");
|
||||
function decodeEntities(value) {
|
||||
hiddenPre.innerHTML=value.replace(/</g,"<");
|
||||
return hiddenPre.innerText || hiddenPre.textContent || '';
|
||||
if (!value) { return ''; }
|
||||
|
||||
// Note: IE8 does not preserve spaces at the start/end of innerHTML
|
||||
// so we must capture them and reattach them afterward
|
||||
var parts = spaceRe.exec(value);
|
||||
var spaceBefore = parts[1];
|
||||
var spaceAfter = parts[3];
|
||||
var content = parts[2];
|
||||
if (content) {
|
||||
hiddenPre.innerHTML=content.replace(/</g,"<");
|
||||
// innerText depends on styling as it doesn't display hidden elements.
|
||||
// Therefore, it's better to use textContent not to cause unnecessary
|
||||
// reflows. However, IE<9 don't support textContent so the innerText
|
||||
// fallback is necessary.
|
||||
content = 'textContent' in hiddenPre ?
|
||||
hiddenPre.textContent : hiddenPre.innerText;
|
||||
}
|
||||
return spaceBefore + content + spaceAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,7 +422,7 @@ function encodeEntities(value) {
|
||||
* comment: function(text) {}
|
||||
* }
|
||||
*/
|
||||
function htmlSanitizeWriter(buf){
|
||||
function htmlSanitizeWriter(buf, uriValidator){
|
||||
var ignore = false;
|
||||
var out = angular.bind(buf, buf.push);
|
||||
return {
|
||||
@@ -361,12 +431,14 @@ function htmlSanitizeWriter(buf){
|
||||
if (!ignore && specialElements[tag]) {
|
||||
ignore = tag;
|
||||
}
|
||||
if (!ignore && validElements[tag] == true) {
|
||||
if (!ignore && validElements[tag] === true) {
|
||||
out('<');
|
||||
out(tag);
|
||||
angular.forEach(attrs, function(value, key){
|
||||
var lkey=angular.lowercase(key);
|
||||
if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
||||
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background');
|
||||
if (validAttrs[lkey] === true &&
|
||||
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
|
||||
out(' ');
|
||||
out(key);
|
||||
out('="');
|
||||
@@ -379,7 +451,7 @@ function htmlSanitizeWriter(buf){
|
||||
},
|
||||
end: function(tag){
|
||||
tag = angular.lowercase(tag);
|
||||
if (!ignore && validElements[tag] == true) {
|
||||
if (!ignore && validElements[tag] === true) {
|
||||
out('</');
|
||||
out(tag);
|
||||
out('>');
|
||||
@@ -398,30 +470,9 @@ function htmlSanitizeWriter(buf){
|
||||
|
||||
|
||||
// define ngSanitize module and register $sanitize service
|
||||
angular.module('ngSanitize', []).value('$sanitize', $sanitize);
|
||||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngSanitize.directive:ngBindHtml
|
||||
*
|
||||
* @description
|
||||
* Creates a binding that will sanitize the result of evaluating the `expression` with the
|
||||
* {@link ngSanitize.$sanitize $sanitize} service and innerHTML the result into the current element.
|
||||
*
|
||||
* See {@link ngSanitize.$sanitize $sanitize} docs for examples.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
|
||||
*/
|
||||
angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
|
||||
return function(scope, element, attr) {
|
||||
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
|
||||
scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) {
|
||||
value = $sanitize(value);
|
||||
element.html(value || '');
|
||||
});
|
||||
};
|
||||
}]);
|
||||
/* global sanitizeText: false */
|
||||
|
||||
/**
|
||||
* @ngdoc filter
|
||||
@@ -429,10 +480,13 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
||||
* plain email address links.
|
||||
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
||||
* plain email address links.
|
||||
*
|
||||
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
|
||||
*
|
||||
* @param {string} text Input text.
|
||||
* @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
|
||||
* @returns {string} Html-linkified text.
|
||||
*
|
||||
* @usage
|
||||
@@ -449,6 +503,7 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
||||
'mailto:us@somewhere.org,\n'+
|
||||
'another@somewhere.org,\n'+
|
||||
'and one more: ftp://127.0.0.1/.';
|
||||
$scope.snippetWithTarget = 'http://angularjs.org/';
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl">
|
||||
@@ -468,6 +523,15 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
||||
<div ng-bind-html="snippet | linky"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="linky-target">
|
||||
<td>linky target</td>
|
||||
<td>
|
||||
<pre><div ng-bind-html="snippetWithTarget | linky:'_blank'"><br></div></pre>
|
||||
</td>
|
||||
<td>
|
||||
<div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="escaped-html">
|
||||
<td>no filter</td>
|
||||
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
||||
@@ -475,45 +539,50 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
||||
</tr>
|
||||
</table>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
<doc:protractor>
|
||||
it('should linkify the snippet with urls', function() {
|
||||
expect(using('#linky-filter').binding('snippet | linky')).
|
||||
toBe('Pretty text with some links: ' +
|
||||
'<a href="http://angularjs.org/">http://angularjs.org/</a>, ' +
|
||||
'<a href="mailto:us@somewhere.org">us@somewhere.org</a>, ' +
|
||||
'<a href="mailto:another@somewhere.org">another@somewhere.org</a>, ' +
|
||||
'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
|
||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
||||
toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' +
|
||||
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
||||
expect(element.all(by.css('#linky-filter a')).count()).toEqual(4);
|
||||
});
|
||||
|
||||
it ('should not linkify snippet without the linky filter', function() {
|
||||
expect(using('#escaped-html').binding('snippet')).
|
||||
toBe("Pretty text with some links:\n" +
|
||||
"http://angularjs.org/,\n" +
|
||||
"mailto:us@somewhere.org,\n" +
|
||||
"another@somewhere.org,\n" +
|
||||
"and one more: ftp://127.0.0.1/.");
|
||||
it('should not linkify snippet without the linky filter', function() {
|
||||
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()).
|
||||
toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' +
|
||||
'another@somewhere.org, and one more: ftp://127.0.0.1/.');
|
||||
expect(element.all(by.css('#escaped-html a')).count()).toEqual(0);
|
||||
});
|
||||
|
||||
it('should update', function() {
|
||||
input('snippet').enter('new http://link.');
|
||||
expect(using('#linky-filter').binding('snippet | linky')).
|
||||
toBe('new <a href="http://link">http://link</a>.');
|
||||
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
||||
element(by.model('snippet')).clear();
|
||||
element(by.model('snippet')).sendKeys('new http://link.');
|
||||
expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()).
|
||||
toBe('new http://link.');
|
||||
expect(element.all(by.css('#linky-filter a')).count()).toEqual(1);
|
||||
expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText())
|
||||
.toBe('new http://link.');
|
||||
});
|
||||
</doc:scenario>
|
||||
|
||||
it('should work with the target property', function() {
|
||||
expect(element(by.id('linky-target')).
|
||||
element(by.binding("snippetWithTarget | linky:'_blank'")).getText()).
|
||||
toBe('http://angularjs.org/');
|
||||
expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank');
|
||||
});
|
||||
</doc:protractor>
|
||||
</doc:example>
|
||||
*/
|
||||
angular.module('ngSanitize').filter('linky', function() {
|
||||
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
|
||||
angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
|
||||
var LINKY_URL_REGEXP =
|
||||
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/,
|
||||
MAILTO_REGEXP = /^mailto:/;
|
||||
|
||||
return function(text) {
|
||||
return function(text, target) {
|
||||
if (!text) return text;
|
||||
var match;
|
||||
var raw = text;
|
||||
var html = [];
|
||||
// TODO(vojta): use $sanitize instead
|
||||
var writer = htmlSanitizeWriter(html);
|
||||
var url;
|
||||
var i;
|
||||
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
||||
@@ -522,16 +591,35 @@ angular.module('ngSanitize').filter('linky', function() {
|
||||
// if we did not match ftp/http/mailto then assume mailto
|
||||
if (match[2] == match[3]) url = 'mailto:' + url;
|
||||
i = match.index;
|
||||
writer.chars(raw.substr(0, i));
|
||||
writer.start('a', {href:url});
|
||||
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
||||
writer.end('a');
|
||||
addText(raw.substr(0, i));
|
||||
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
|
||||
raw = raw.substring(i + match[0].length);
|
||||
}
|
||||
writer.chars(raw);
|
||||
return html.join('');
|
||||
addText(raw);
|
||||
return $sanitize(html.join(''));
|
||||
|
||||
function addText(text) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
html.push(sanitizeText(text));
|
||||
}
|
||||
|
||||
function addLink(url, text) {
|
||||
html.push('<a ');
|
||||
if (angular.isDefined(target)) {
|
||||
html.push('target="');
|
||||
html.push(target);
|
||||
html.push('" ');
|
||||
}
|
||||
html.push('href="');
|
||||
html.push(url);
|
||||
html.push('">');
|
||||
addText(text);
|
||||
html.push('</a>');
|
||||
}
|
||||
};
|
||||
});
|
||||
}]);
|
||||
|
||||
|
||||
})(window, window.angular);
|
||||
Vendored
Executable → Regular
+18631
-12061
File diff suppressed because it is too large.
Load diff
Vendored
Executable → Regular
+12048
-6021
File diff suppressed because it is too large.
Load diff
+222
-195
@@ -1,195 +1,222 @@
|
||||
/**
|
||||
* Enhanced Select2 Dropmenus
|
||||
*
|
||||
* @AJAX Mode - When in this mode, your value will be an object (or array of objects) of the data used by Select2
|
||||
* This change is so that you do not have to do an additional query yourself on top of Select2's own query
|
||||
* @params [options] {object} The configuration options passed to $.fn.select2(). Refer to the documentation
|
||||
*/
|
||||
angular.module('ui.select2', []).value('uiSelect2Config', {}).directive('uiSelect2', ['uiSelect2Config', '$timeout', function (uiSelect2Config, $timeout) {
|
||||
var options = {};
|
||||
if (uiSelect2Config) {
|
||||
angular.extend(options, uiSelect2Config);
|
||||
}
|
||||
return {
|
||||
require: 'ngModel',
|
||||
compile: function (tElm, tAttrs) {
|
||||
var watch,
|
||||
repeatOption,
|
||||
repeatAttr,
|
||||
isSelect = tElm.is('select'),
|
||||
isMultiple = (tAttrs.multiple !== undefined);
|
||||
|
||||
// Enable watching of the options dataset if in use
|
||||
if (tElm.is('select')) {
|
||||
repeatOption = tElm.find('option[ng-repeat], option[data-ng-repeat]');
|
||||
|
||||
if (repeatOption.length) {
|
||||
repeatAttr = repeatOption.attr('ng-repeat') || repeatOption.attr('data-ng-repeat');
|
||||
watch = jQuery.trim(repeatAttr.split('|')[0]).split(' ').pop();
|
||||
}
|
||||
}
|
||||
|
||||
return function (scope, elm, attrs, controller) {
|
||||
// instance-specific options
|
||||
var opts = angular.extend({}, options, scope.$eval(attrs.uiSelect2));
|
||||
|
||||
/*
|
||||
Convert from Select2 view-model to Angular view-model.
|
||||
*/
|
||||
var convertToAngularModel = function(select2_data) {
|
||||
var model;
|
||||
if (opts.simple_tags) {
|
||||
model = []
|
||||
angular.forEach(select2_data, function(value, index) {
|
||||
model.push(value.id)
|
||||
})
|
||||
} else {
|
||||
model = select2_data
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
/*
|
||||
Convert from Angular view-model to Select2 view-model.
|
||||
*/
|
||||
var convertToSelect2Model = function(angular_data) {
|
||||
var model = []
|
||||
if (!angular_data) {
|
||||
return model;
|
||||
}
|
||||
|
||||
if (opts.simple_tags) {
|
||||
model = [];
|
||||
angular.forEach(
|
||||
angular_data,
|
||||
function(value, index) {
|
||||
model.push({'id': value, 'text': value});
|
||||
})
|
||||
} else {
|
||||
model = angular_data;
|
||||
}
|
||||
return model
|
||||
}
|
||||
|
||||
if (isSelect) {
|
||||
// Use <select multiple> instead
|
||||
delete opts.multiple;
|
||||
delete opts.initSelection;
|
||||
} else if (isMultiple) {
|
||||
opts.multiple = true;
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
// Watch the model for programmatic changes
|
||||
scope.$watch(tAttrs.ngModel, function(current, old) {
|
||||
if (!current) {
|
||||
return
|
||||
}
|
||||
if (current == old) {
|
||||
return
|
||||
}
|
||||
controller.$render()
|
||||
}, true)
|
||||
controller.$render = function () {
|
||||
if (isSelect) {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
} else {
|
||||
if (opts.multiple) {
|
||||
elm.select2(
|
||||
'data', convertToSelect2Model(controller.$viewValue));
|
||||
} else {
|
||||
if (angular.isObject(controller.$viewValue)) {
|
||||
elm.select2('data', controller.$viewValue);
|
||||
} else if (!controller.$viewValue) {
|
||||
elm.select2('data', null);
|
||||
} else {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Watch the options dataset for changes
|
||||
if (watch) {
|
||||
scope.$watch(watch, function (newVal, oldVal, scope) {
|
||||
if (!newVal) return;
|
||||
// Delayed so that the options have time to be rendered
|
||||
$timeout(function () {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
// Refresh angular to remove the superfluous option
|
||||
elm.trigger('change');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Update valid and dirty statuses
|
||||
controller.$parsers.push(function (value) {
|
||||
var div = elm.prev()
|
||||
div
|
||||
.toggleClass('ng-invalid', !controller.$valid)
|
||||
.toggleClass('ng-valid', controller.$valid)
|
||||
.toggleClass('ng-invalid-required', !controller.$valid)
|
||||
.toggleClass('ng-valid-required', controller.$valid)
|
||||
.toggleClass('ng-dirty', controller.$dirty)
|
||||
.toggleClass('ng-pristine', controller.$pristine);
|
||||
return value;
|
||||
});
|
||||
|
||||
if (!isSelect) {
|
||||
// Set the view and model value and update the angular template manually for the ajax/multiple select2.
|
||||
elm.bind("change", function () {
|
||||
if (scope.$$phase) return;
|
||||
scope.$apply(function () {
|
||||
controller.$setViewValue(
|
||||
convertToAngularModel(elm.select2('data')));
|
||||
});
|
||||
});
|
||||
|
||||
if (opts.initSelection) {
|
||||
var initSelection = opts.initSelection;
|
||||
opts.initSelection = function (element, callback) {
|
||||
initSelection(element, function (value) {
|
||||
controller.$setViewValue(convertToAngularModel(value));
|
||||
callback(value);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elm.bind("$destroy", function() {
|
||||
elm.select2("destroy");
|
||||
});
|
||||
|
||||
attrs.$observe('disabled', function (value) {
|
||||
elm.select2('enable', !value);
|
||||
});
|
||||
|
||||
attrs.$observe('readonly', function (value) {
|
||||
elm.select2('readonly', !!value);
|
||||
});
|
||||
|
||||
if (attrs.ngMultiple) {
|
||||
scope.$watch(attrs.ngMultiple, function(newVal) {
|
||||
elm.select2(opts);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the plugin late so that the injected DOM does not disrupt the template compiler
|
||||
$timeout(function () {
|
||||
elm.select2(opts);
|
||||
|
||||
// Set initial value - I'm not sure about this but it seems to need to be there
|
||||
elm.val(controller.$viewValue);
|
||||
// important!
|
||||
controller.$render();
|
||||
|
||||
// Not sure if I should just check for !isSelect OR if I should check for 'tags' key
|
||||
if (!opts.initSelection && !isSelect)
|
||||
controller.$setViewValue(
|
||||
convertToAngularModel(elm.select2('data')));
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
/**
|
||||
* Enhanced Select2 Dropmenus
|
||||
*
|
||||
* @AJAX Mode - When in this mode, your value will be an object (or array of objects) of the data used by Select2
|
||||
* This change is so that you do not have to do an additional query yourself on top of Select2's own query
|
||||
* @params [options] {object} The configuration options passed to $.fn.select2(). Refer to the documentation
|
||||
*/
|
||||
angular.module('ui.select2', []).value('uiSelect2Config', {}).directive('uiSelect2', ['uiSelect2Config', '$timeout', function (uiSelect2Config, $timeout) {
|
||||
var options = {};
|
||||
if (uiSelect2Config) {
|
||||
angular.extend(options, uiSelect2Config);
|
||||
}
|
||||
return {
|
||||
require: 'ngModel',
|
||||
priority: 1,
|
||||
compile: function (tElm, tAttrs) {
|
||||
var watch,
|
||||
repeatOption,
|
||||
repeatAttr,
|
||||
isSelect = tElm.is('select'),
|
||||
isMultiple = angular.isDefined(tAttrs.multiple);
|
||||
|
||||
// Enable watching of the options dataset if in use
|
||||
if (tElm.is('select')) {
|
||||
repeatOption = tElm.find( 'optgroup[ng-repeat], optgroup[data-ng-repeat], option[ng-repeat], option[data-ng-repeat]');
|
||||
|
||||
if (repeatOption.length) {
|
||||
repeatAttr = repeatOption.attr('ng-repeat') || repeatOption.attr('data-ng-repeat');
|
||||
watch = jQuery.trim(repeatAttr.split('|')[0]).split(' ').pop();
|
||||
}
|
||||
}
|
||||
|
||||
return function (scope, elm, attrs, controller) {
|
||||
// instance-specific options
|
||||
var opts = angular.extend({}, options, scope.$eval(attrs.uiSelect2));
|
||||
|
||||
/*
|
||||
Convert from Select2 view-model to Angular view-model.
|
||||
*/
|
||||
var convertToAngularModel = function(select2_data) {
|
||||
var model;
|
||||
if (opts.simple_tags) {
|
||||
model = [];
|
||||
angular.forEach(select2_data, function(value, index) {
|
||||
model.push(value.id);
|
||||
});
|
||||
} else {
|
||||
model = select2_data;
|
||||
}
|
||||
return model;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert from Angular view-model to Select2 view-model.
|
||||
*/
|
||||
var convertToSelect2Model = function(angular_data) {
|
||||
var model = [];
|
||||
if (!angular_data) {
|
||||
return model;
|
||||
}
|
||||
|
||||
if (opts.simple_tags) {
|
||||
model = [];
|
||||
angular.forEach(
|
||||
angular_data,
|
||||
function(value, index) {
|
||||
model.push({'id': value, 'text': value});
|
||||
});
|
||||
} else {
|
||||
model = angular_data;
|
||||
}
|
||||
return model;
|
||||
};
|
||||
|
||||
if (isSelect) {
|
||||
// Use <select multiple> instead
|
||||
delete opts.multiple;
|
||||
delete opts.initSelection;
|
||||
} else if (isMultiple) {
|
||||
opts.multiple = true;
|
||||
}
|
||||
|
||||
if (controller) {
|
||||
// Watch the model for programmatic changes
|
||||
scope.$watch(tAttrs.ngModel, function(current, old) {
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
if (current === old) {
|
||||
return;
|
||||
}
|
||||
controller.$render();
|
||||
}, true);
|
||||
controller.$render = function () {
|
||||
if (isSelect) {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
} else {
|
||||
if (opts.multiple) {
|
||||
var viewValue = controller.$viewValue;
|
||||
if (angular.isString(viewValue)) {
|
||||
viewValue = viewValue.split(',');
|
||||
}
|
||||
elm.select2(
|
||||
'data', convertToSelect2Model(viewValue));
|
||||
} else {
|
||||
if (angular.isObject(controller.$viewValue)) {
|
||||
elm.select2('data', controller.$viewValue);
|
||||
} else if (!controller.$viewValue) {
|
||||
elm.select2('data', null);
|
||||
} else {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Watch the options dataset for changes
|
||||
if (watch) {
|
||||
scope.$watch(watch, function (newVal, oldVal, scope) {
|
||||
if (angular.equals(newVal, oldVal)) {
|
||||
return;
|
||||
}
|
||||
// Delayed so that the options have time to be rendered
|
||||
$timeout(function () {
|
||||
elm.select2('val', controller.$viewValue);
|
||||
// Refresh angular to remove the superfluous option
|
||||
elm.trigger('change');
|
||||
if(newVal && !oldVal && controller.$setPristine) {
|
||||
controller.$setPristine(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Update valid and dirty statuses
|
||||
controller.$parsers.push(function (value) {
|
||||
var div = elm.prev();
|
||||
div
|
||||
.toggleClass('ng-invalid', !controller.$valid)
|
||||
.toggleClass('ng-valid', controller.$valid)
|
||||
.toggleClass('ng-invalid-required', !controller.$valid)
|
||||
.toggleClass('ng-valid-required', controller.$valid)
|
||||
.toggleClass('ng-dirty', controller.$dirty)
|
||||
.toggleClass('ng-pristine', controller.$pristine);
|
||||
return value;
|
||||
});
|
||||
|
||||
if (!isSelect) {
|
||||
// Set the view and model value and update the angular template manually for the ajax/multiple select2.
|
||||
elm.bind("change", function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (scope.$$phase || scope.$root.$$phase) {
|
||||
return;
|
||||
}
|
||||
scope.$apply(function () {
|
||||
controller.$setViewValue(
|
||||
convertToAngularModel(elm.select2('data')));
|
||||
});
|
||||
});
|
||||
|
||||
if (opts.initSelection) {
|
||||
var initSelection = opts.initSelection;
|
||||
opts.initSelection = function (element, callback) {
|
||||
initSelection(element, function (value) {
|
||||
var isPristine = controller.$pristine;
|
||||
controller.$setViewValue(convertToAngularModel(value));
|
||||
callback(value);
|
||||
if (isPristine) {
|
||||
controller.$setPristine();
|
||||
}
|
||||
elm.prev().toggleClass('ng-pristine', controller.$pristine);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elm.bind("$destroy", function() {
|
||||
elm.select2("destroy");
|
||||
});
|
||||
|
||||
attrs.$observe('disabled', function (value) {
|
||||
elm.select2('enable', !value);
|
||||
});
|
||||
|
||||
attrs.$observe('readonly', function (value) {
|
||||
elm.select2('readonly', !!value);
|
||||
});
|
||||
|
||||
if (attrs.ngMultiple) {
|
||||
scope.$watch(attrs.ngMultiple, function(newVal) {
|
||||
attrs.$set('multiple', !!newVal);
|
||||
elm.select2(opts);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the plugin late so that the injected DOM does not disrupt the template compiler
|
||||
$timeout(function () {
|
||||
elm.select2(opts);
|
||||
|
||||
// Set initial value - I'm not sure about this but it seems to need to be there
|
||||
elm.select2('data', controller.$modelValue);
|
||||
// important!
|
||||
controller.$render();
|
||||
|
||||
// Not sure if I should just check for !isSelect OR if I should check for 'tags' key
|
||||
if (!opts.initSelection && !isSelect) {
|
||||
var isPristine = controller.$pristine;
|
||||
controller.$setViewValue(
|
||||
convertToAngularModel(elm.select2('data'))
|
||||
);
|
||||
if (isPristine) {
|
||||
controller.$setPristine();
|
||||
}
|
||||
elm.prev().toggleClass('ng-pristine', controller.$pristine);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
|
||||
<li data-ng-show="!application.bearerOnly && !application.publicClient"><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 class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</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}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<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">Claims</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> Allowed Claims</h2>
|
||||
<form class="form-horizontal" name="claimForm">
|
||||
<div data-ng-include data-src="'partials/claims.html'"></div>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+5
-3
@@ -5,8 +5,10 @@
|
||||
<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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb" data-ng-hide="create">
|
||||
@@ -16,7 +18,7 @@
|
||||
<li class="active">Credentials</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> Credentials</h2>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageApplications">
|
||||
<fieldset >
|
||||
<legend><span class="text">Client Secret</span></legend>
|
||||
<div class="form-group">
|
||||
@@ -27,7 +29,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions">
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
|
||||
<button type="submit" data-ng-click="changePassword()" class="btn btn-primary btn-lg">Regenerate Secret
|
||||
</button>
|
||||
</div>
|
||||
|
||||
+48
-34
@@ -2,11 +2,13 @@
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb" data-ng-show="create">
|
||||
@@ -23,7 +25,7 @@
|
||||
<li class="active">Settings</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> Settings</h2>
|
||||
<form class="form-horizontal" name="applicationForm" novalidate>
|
||||
<form class="form-horizontal" name="applicationForm" novalidate kc-read-only="!access.manageApplications">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="create">*</span></label>
|
||||
@@ -37,6 +39,44 @@
|
||||
<input ng-model="application.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="clientType">Client Type</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="clientType"
|
||||
ng-change="changeClientType()"
|
||||
ng-model="clientType"
|
||||
ng-options="cType for cType in clientTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="!application.bearerOnly">
|
||||
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI <span class="required" data-ng-show="create">*</span></label>
|
||||
<div class="col-sm-6">
|
||||
<div ng-repeat="redirectUri in application.redirectUris" class="row kc-item-deletable">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="redirectUri" id="redirectUri" data-ng-model="redirectUri" readonly />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-danger" type="button" data-ng-click="deleteRedirectUri($index)">
|
||||
Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" name="newRedirectUri" id="newRedirectUri"
|
||||
placeholder="New Redirect URI..." data-ng-model="newRedirectUri"
|
||||
data-ng-class="{'input-below':application.redirectUris.length}" />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-primary" data-ng-click="addRedirectUri()" ng-show="newRedirectUri.length > 0">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="baseUrl">Base URL</label>
|
||||
<div class="col-sm-4">
|
||||
@@ -53,9 +93,9 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="col-sm-6">
|
||||
<div ng-repeat="webOrigin in application.webOrigins" class="row kc-item-deletable">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control kc-button-control"
|
||||
type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="webOrigin" id="webOrigin"
|
||||
@@ -67,7 +107,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control kc-button-control"
|
||||
type="text" name="newWebOrigin" id="newWebOrigin"
|
||||
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
|
||||
@@ -80,39 +120,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI</label>
|
||||
<div class="col-sm-4">
|
||||
<div ng-repeat="redirectUri in application.redirectUris" class="row kc-item-deletable">
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="redirectUri" id="redirectUri" data-ng-model="redirectUri" readonly />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-danger" type="button" data-ng-click="deleteRedirectUri($index)">
|
||||
Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" type="text" name="newRedirectUri" id="newRedirectUri"
|
||||
placeholder="New Redirect URI..." data-ng-model="newRedirectUri"
|
||||
data-ng-class="{'input-below':application.redirectUris.length}" />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-primary" data-ng-click="addRedirectUri()" ng-show="newRedirectUri.length > 0">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="create">
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageApplications">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!create">
|
||||
<div class="pull-right form-actions" data-ng-show="!create && access.manageApplications">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
|
||||
+10
-7
@@ -3,19 +3,22 @@
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="top-nav" data-ng-show="create">
|
||||
<ul class="rcue-tabs">
|
||||
<li></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">Installation</li>
|
||||
</ol>
|
||||
<h2>Application Installation</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<th>Base URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-show="applications && applications.length > 5"> <!-- todo -->
|
||||
<!--<tfoot data-ng-show="applications && applications.length > 5">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="table-nav">
|
||||
@@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</tfoot>-->
|
||||
<tbody>
|
||||
<tr ng-repeat="app in applications | filter:search">
|
||||
<td><a href="#/realms/{{realm.realm}}/applications/{{app.name}}">{{app.name}}</a></td>
|
||||
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
|
||||
<li data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/">{{realm.realm}}</a></li>
|
||||
<li class="active">Revocation</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> Revocation Policies</h2>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="notBefore">Not Before</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
|
||||
<button type="submit" data-ng-click="clear()" class="btn btn-default btn-lg">Clear
|
||||
</button>
|
||||
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-primary btn-lg">Set To Now
|
||||
</button>
|
||||
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary btn-lg">Push
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+7
-5
@@ -2,11 +2,13 @@
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -29,7 +31,7 @@
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> {{role.name}}</h2>
|
||||
<h2 data-ng-show="create"><span>{{application.name}}</span> Add Role</h2>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageApplications">
|
||||
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
|
||||
|
||||
<fieldset class="border-top">
|
||||
@@ -134,11 +136,11 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="create">
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageApplications">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!create">
|
||||
<div class="pull-right form-actions" data-ng-show="!create && access.manageApplications">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
|
||||
+9
-5
@@ -3,11 +3,13 @@
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -21,14 +23,14 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<th class="kc-table-actions" colspan="3" data-ng-show="access.manageApplications">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}/applications/{{application.name}}">Add Role</a>
|
||||
<!-- <button class="remove disabled">Remove</button> -->
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="roles && roles.length > 5">
|
||||
<!--<tr data-ng-show="roles && roles.length > 5">
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="search-comp clearfix">
|
||||
<input type="text" placeholder="Search..." class="search">
|
||||
@@ -39,13 +41,14 @@
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
-->
|
||||
<tr data-ng-hide="!roles || roles.length == 0">
|
||||
<th>Role Name</th>
|
||||
<th>Composite</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-show="roles && roles.length > 5"> <!-- todo -->
|
||||
<!--<tfoot data-ng-show="roles && roles.length > 5">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="table-nav">
|
||||
@@ -57,6 +60,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
-->
|
||||
<tbody>
|
||||
<tr ng-repeat="role in roles">
|
||||
<td><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles/{{role.name}}">{{role.name}}</a></td>
|
||||
|
||||
+6
-4
@@ -3,11 +3,13 @@
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
|
||||
<li><a href="#">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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
|
||||
<li data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -19,7 +21,7 @@
|
||||
</ol>
|
||||
<h2><span>{{application.name}}</span> Scope Mappings</h2>
|
||||
<p class="subtitle"></p>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageApplications">
|
||||
<fieldset>
|
||||
<legend><span class="text">Realm Roles</span></legend>
|
||||
<div class="form-group col-sm-10">
|
||||
@@ -59,7 +61,7 @@
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<div class="select-kc">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications|remove:application:'id')">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications|remove:application:'id')" ng-disabled="false">
|
||||
<option value="" selected> Select an Application </option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
+49
-11
@@ -1,22 +1,60 @@
|
||||
<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">
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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 data-ng-show="!application.bearerOnly && !application.publicClient"><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}}/claims">Claims</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}}/revocation">Revocation</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<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 class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}">{{application.name}}</a></li>
|
||||
<li class="active">Application Sessions</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{application.name}}</span> Sessions (Placeholder Page)</h2>
|
||||
<h2><span>{{application.name}}</span> Sessions</h2>
|
||||
<form class="form-horizontal" name="sessionStats">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="activeSessions">Active Sessions</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="activeSessions" name="activeSessions" data-ng-model="stats.activeSessions" ng-disabled="true">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="activeUsers">Active Users</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="activeUsers" name="activeUsers" data-ng-model="stats.activeUsers" ng-disabled="true">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<table class="table" data-ng-show="stats.activeSessions > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" ng-click="logoutAll()">Invalidate All Sessions</a>
|
||||
<a class="btn btn-primary" ng-click="loadUsers()">Show Users</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Login Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="(user, data) in users">
|
||||
<td><a href="#/realms/{{realm.realm}}/users/{{user}}">{{user}}</a></td>
|
||||
<td>{{data.whenLoggedIn | date:'medium'}}</td>
|
||||
<td><a ng-click="logoutUser(user)">invalidate session</a> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,62 @@
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="username">Username</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.username" name="username" id="username" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="claimName">Name</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.name" name="claimName" id="claimName" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="email">Email</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.email" name="email" id="email" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="gender">Gender</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.gender" name="gender" id="gender" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="address">Address</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.address" name="address" id="address" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="locale">Locale</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.locale" name="locale" id="locale" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="phone">Phone</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.phone" name="phone" id="phone" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="profile">Profile URL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.profile" name="profile" id="profile" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="picture">Picture URL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.picture" name="picture" id="picture" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="website">Website</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="claims.website" name="website" id="website" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -1,43 +1,47 @@
|
||||
<nav id="kc-navigation" class="navbar" role="navigation">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<h1 class="navbar-title"></h1>
|
||||
<div class="container">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<h1 class="navbar-title">Keycloak</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.loggedIn">
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="pficon pficon-user"></span>
|
||||
{{auth.user.displayName}}<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/auth/rest/realms/keycloak-admin/account?referrer=admin-console">Manage Account</a></li>
|
||||
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-primary persistent-secondary" data-ng-controller="RealmDropdownCtrl">
|
||||
<li class="dropdown context" data-ng-show="showNav()">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
{{current.realm.realm}}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-ng-repeat="realm in current.realms">
|
||||
<a href="" ng-click="changeRealm(realm.realm)">{{realm.realm}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="active pull-right" data-ng-show="auth.loggedIn">
|
||||
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="container">
|
||||
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.loggedIn">
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="pficon pficon-user"></span>
|
||||
{{auth.user.displayName}}<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/auth/rest/realms/{{auth.user.realm}}/account?referrer=admin-console">Manage Account</a></li>
|
||||
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-primary persistent-secondary" data-ng-controller="RealmDropdownCtrl">
|
||||
<li class="dropdown context" data-ng-show="showNav()">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
{{current.realm.realm}}
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-ng-repeat="realm in current.realms">
|
||||
<a href="" ng-click="changeRealm(realm.realm)">{{realm.realm}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="active pull-right" data-ng-show="auth.loggedIn && access.createRealm">
|
||||
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
|
||||
data-ng-show="auth.loggedIn">Add Realm</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- TODO remove once this page is properly styled -->
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
|
||||
<li data-ng-show="!oauth.publicClient"><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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Allowed Claims</h2>
|
||||
<form class="form-horizontal" name="claimForm">
|
||||
<div data-ng-include data-src="'partials/claims.html'"></div>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageClients">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+4
-2
@@ -3,8 +3,10 @@
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -15,7 +17,7 @@
|
||||
<li class="active">Credentials</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Credentials</h2>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageClients">
|
||||
<fieldset >
|
||||
<legend><span class="text">Client Secret</span></legend>
|
||||
<div class="form-group">
|
||||
@@ -26,7 +28,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions">
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageClients">
|
||||
<button type="submit" data-ng-click="changePassword()" class="btn btn-primary btn-lg">Regenerate Secret
|
||||
</button>
|
||||
</div>
|
||||
|
||||
+42
-28
@@ -2,9 +2,11 @@
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!oauth.publicClient"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb" data-ng-show="create">
|
||||
@@ -21,7 +23,7 @@
|
||||
<li class="active">Settings</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Settings</h2>
|
||||
<form class="form-horizontal" name="oauthForm" novalidate>
|
||||
<form class="form-horizontal" name="oauthForm" novalidate kc-read-only="!access.manageClients">
|
||||
<fieldset class="border-top">
|
||||
|
||||
<div class="form-group">
|
||||
@@ -39,35 +41,22 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
|
||||
<label class="col-sm-2 control-label" for="clientType">Client Type</label>
|
||||
<div class="col-sm-4">
|
||||
<div ng-repeat="webOrigin in oauth.webOrigins" class="kc-item-deletable row">
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="webOrigin" id="webOrigin" data-ng-model="webOrigin" readonly />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-danger" type="button" data-ng-click="deleteWebOrigin($index)">
|
||||
Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" type="text" name="newWebOrigin" id="newWebOrigin"
|
||||
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
|
||||
data-ng-class="{'input-below':oauth.webOrigins.length}" />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-primary" data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
|
||||
</div>
|
||||
<div class="select-kc">
|
||||
<select id="clientType"
|
||||
ng-change="changeClientType()"
|
||||
ng-model="clientType"
|
||||
ng-options="cType for cType in clientTypes">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI</label>
|
||||
<div class="col-sm-4">
|
||||
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI <span class="required" data-ng-show="create">*</span></label>
|
||||
<div class="col-sm-6">
|
||||
<div ng-repeat="redirectUri in oauth.redirectUris" class="kc-item-deletable row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="redirectUri" id="redirectUri" data-ng-model="redirectUri" readonly />
|
||||
</div>
|
||||
@@ -77,7 +66,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" name="newRedirectUri" id="newRedirectUri"
|
||||
placeholder="New Redirect URI..." data-ng-model="newRedirectUri"
|
||||
data-ng-class="{'input-below':oauth.redirectUris.length}" />
|
||||
@@ -88,13 +77,38 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
|
||||
<div class="col-sm-6">
|
||||
<div ng-repeat="webOrigin in oauth.webOrigins" class="kc-item-deletable row">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
|
||||
name="webOrigin" id="webOrigin" data-ng-model="webOrigin" readonly />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-danger" type="button" data-ng-click="deleteWebOrigin($index)">
|
||||
Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" type="text" name="newWebOrigin" id="newWebOrigin"
|
||||
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
|
||||
data-ng-class="{'input-below':oauth.webOrigins.length}" />
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<button class="btn btn-primary" data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="create">
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageClients">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!create">
|
||||
<div class="pull-right form-actions" data-ng-show="!create && access.manageClients">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
|
||||
+3
-1
@@ -2,9 +2,11 @@
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!oauth.publicClient"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<h2>OAuth Client Installation</h2>
|
||||
|
||||
+7
-6
@@ -14,15 +14,15 @@
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="search-comp clearfix">
|
||||
<input type="text" placeholder="Search..." class="form-control search"
|
||||
<input type="text" placeholder="Search..." class="form-control search" data-ng-model="search.name"
|
||||
onkeyup="if(event.keyCode == 13){$(this).next('button').click();}">
|
||||
<button class="kc-icon-search" tooltip-placement="right"
|
||||
tooltip="Search by oauth client name">
|
||||
<button type="submit" class="kc-icon-search" tooltip-placement="right"
|
||||
tooltip="Search by application name.">
|
||||
Icon: search
|
||||
</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" href="#/create/oauth-client/{{realm.realm}}">Add OAuth Client</a>
|
||||
<a class="btn btn-primary" href="#/create/application/{{realm.realm}}">Add Application</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
@@ -31,7 +31,7 @@
|
||||
<th>Enabled</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-show="oauthClients && oauthClients.length > 5"> <!-- todo -->
|
||||
<!--<tfoot data-ng-show="oauthClients && oauthClients.length > 5">
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div class="table-nav">
|
||||
@@ -43,8 +43,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
-->
|
||||
<tbody>
|
||||
<tr ng-repeat="client in oauthClients">
|
||||
<tr ng-repeat="client in oauthClients | filter:search">
|
||||
<td><a href="#/realms/{{realm.realm}}/oauth-clients/{{client.id}}">{{client.name}}</a></td>
|
||||
<td>{{client.enabled}}</td>
|
||||
</tr>
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">Settings</a></li>
|
||||
<li data-ng-show="!oauth.publicClient"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</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>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}">{{oauth.name}}</a></li>
|
||||
<li class="active">Revocation</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Revocation Policies</h2>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="notBefore">Not Before</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
|
||||
<button type="submit" data-ng-click="clear()" class="btn btn-default btn-lg">Clear
|
||||
</button>
|
||||
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-primary btn-lg">Set To Now
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+5
-3
@@ -3,9 +3,11 @@
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="!oauth.publicClient"><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/claims">Claims</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>
|
||||
<li><a href="#/realms/{{realm.realm}}/oauth-clients/{{oauth.id}}/revocation">Revocation</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -17,7 +19,7 @@
|
||||
</ol>
|
||||
<h2><span>{{oauth.name}}</span> Scope Mappings</h2>
|
||||
<p class="subtitle"></p>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients">
|
||||
<fieldset>
|
||||
<legend><span class="text">Realm Roles</span></legend>
|
||||
<div class="form-group col-sm-10">
|
||||
@@ -57,7 +59,7 @@
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<div class="select-kc">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications)">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications)" ng-disabled="false">
|
||||
<option value="" selected> Select an Application </option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="bs-sidebar col-sm-3 "></div>
|
||||
<div id="content-area" class="col-sm-9" role="main">
|
||||
<div id="content">
|
||||
<h2>Add Realm</h2>
|
||||
<h2 class="margin-top">Add Realm</h2>
|
||||
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
|
||||
|
||||
+4
-4
@@ -9,9 +9,9 @@
|
||||
<li class="active">Required Credentials</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Credentials</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<legend uncollapsed><span class="text">Realm Credentials Settings</span></legend>
|
||||
<legend><span class="text">Realm Credentials Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="user" class="control-label two-lines">Required User Credentials</label>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="border-top">
|
||||
<legend uncollapsed><span class="text">Realm Password Policy</span></legend>
|
||||
<legend><span class="text">Realm Password Policy</span></legend>
|
||||
<table class="table">
|
||||
<caption class="hidden">Table of Password Policies</caption>
|
||||
<thead>
|
||||
@@ -63,7 +63,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions">
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
<li class="active">Registration</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Default Roles</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset>
|
||||
<legend><span class="text">Realm Default Roles</span> </legend>
|
||||
<div class="form-group">
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<div class="select-kc">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications" ng-disabled="false">
|
||||
<option value="" selected> Select an Application...</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -7,98 +7,108 @@
|
||||
<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>
|
||||
<h2 data-ng-hide="createRealm"><span>{{realm.realm}}</span> General Settings</h2>
|
||||
<p class="subtitle" data-ng-show="createRealm"><span class="required">*</span> Required fields</p>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset>
|
||||
<legend class="aj-collapse open"><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="createRealm">*</span></label>
|
||||
<div data-ng-show="access.viewRealm">
|
||||
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</h2>
|
||||
<h2 data-ng-hide="createRealm"><span>{{realm.realm}}</span> General Settings</h2>
|
||||
<p class="subtitle" data-ng-show="createRealm"><span class="required">*</span> Required fields</p>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset>
|
||||
<legend class="aj-collapse open"><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="createRealm">*</span></label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="name" name="name" data-ng-model="realm.realm" autofocus required>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="text" id="name" name="name" data-ng-model="realm.realm" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="enabled">Enabled</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="enabled">Enabled</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.enabled" name="enabled" id="enabled" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Login Options</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="social">Social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.social" name="social" id="social" onoffswitch />
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Login Options</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="social">Social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.social" name="social" id="social" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-ng-show="realm.social">
|
||||
<label class="col-sm-2 control-label" for="updateProfileOnInitialSocialLogin">Update profile on first social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.updateProfileOnInitialSocialLogin" name="updateProfileOnInitialSocialLogin" id="updateProfileOnInitialSocialLogin" onoffswitch />
|
||||
<div class="form-group" data-ng-show="realm.social">
|
||||
<label class="col-sm-2 control-label" for="updateProfileOnInitialSocialLogin">Update profile on first social login</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.updateProfileOnInitialSocialLogin" name="updateProfileOnInitialSocialLogin" id="updateProfileOnInitialSocialLogin" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="registrationAllowed" class="col-sm-2 control-label">User registration</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="registrationAllowed" class="col-sm-2 control-label">User registration</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.registrationAllowed" name="registrationAllowed" id="registrationAllowed" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="resetPasswordAllowed" class="col-sm-2 control-label">Reset password</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="resetPasswordAllowed" class="col-sm-2 control-label">Reset password</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.resetPasswordAllowed" name="resetPasswordAllowed" id="resetPasswordAllowed" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="verifyEmail" class="col-sm-2 control-label">Verify email</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="verifyEmail" class="col-sm-2 control-label">Verify email</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.verifyEmail" name="verifyEmail" id="verifyEmail" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="requireSsl" class="col-sm-2 control-label">Require SSL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
|
||||
<div class="form-group">
|
||||
<label for="requireSsl" class="col-sm-2 control-label">Require SSL</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.requireSsl" name="requireSsl" id="requireSsl" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Optional Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="loginTheme">Login Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="loginTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.loginTheme"
|
||||
data-kc-options="serverInfo.themes.login">
|
||||
</select>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend><span class="text">Optional Settings</span></legend>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="loginTheme">Login Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="loginTheme"
|
||||
ng-model="realm.loginTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.login">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accountTheme">Account Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<select kc-select id="accountTheme"
|
||||
data-kc-placeholder="Select one..."
|
||||
data-kc-model="realm.accountTheme"
|
||||
data-kc-options="serverInfo.themes.account">
|
||||
</select>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accountTheme">Account Theme</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="select-kc">
|
||||
<select id="accountTheme"
|
||||
ng-model="realm.accountTheme"
|
||||
ng-options="o as o for o in serverInfo.themes.account">
|
||||
<option value="" disabled selected>Select one...</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="createRealm && access.manageRealm">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="!createRealm && access.manageRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div data-ng-hide="access.viewRealm">
|
||||
<h2 ><span>{{realm.realm}}</span></h2>
|
||||
</div>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="createRealm">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
<div class="pull-right form-actions" data-ng-show="!createRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -8,7 +8,7 @@
|
||||
<li class="active">Keys</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Keys</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="publicKey">Public key</label>
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions">
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||
<button class="btn btn-primary btn-lg" type="submit" data-ng-click="generate()">Generate new keys</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,34 +1,25 @@
|
||||
<div id="wrapper" class="container">
|
||||
<div class="row">
|
||||
<div class="bs-sidebar col-md-3 clearfix">
|
||||
<ul data-ng-hide="createRealm">
|
||||
<li class="active"><a href="#/realms">Realms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<div class="top-nav" data-ng-hide="createRealm">
|
||||
<ul class="rcue-tabs">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
||||
<h1>
|
||||
<span class="gray">Realms</span>
|
||||
</h1>
|
||||
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Realm</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr data-ng-repeat="r in realms">
|
||||
<td><a href="#/realms/{{r.realm}}">{{r.realm}}</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-right-bg"></div>
|
||||
<div class="bs-sidebar col-sm-3 ">
|
||||
<ul data-ng-hide="createRealm">
|
||||
<li class="active"><a href="#/realms">Realms</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li class="active"><a href="">Realm List</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<h2><span>Realms</span></h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Realm</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="r in realms">
|
||||
<td><a href="#/realms/{{r.realm}}">{{r.realm}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</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-show="access.viewRealm" 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] == 'default-roles' || path[2] == 'registration-settings' ||
|
||||
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 data-ng-show="access.viewUsers" 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' || 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>
|
||||
|
||||
<li data-ng-show="access.viewApplications" 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-show="access.viewClients" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
|
||||
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/revocation">Sessions</a></li>
|
||||
</ul>
|
||||
@@ -8,10 +8,10 @@
|
||||
<li class="active">SMTP Configuration</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Email Server Settings</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
|
||||
<fieldset>
|
||||
<legend uncollapsed><span class="text">Required Settings</span></legend>
|
||||
<legend><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="smtpHost">Host <span class="required">*</span></label>
|
||||
<div class="col-sm-4">
|
||||
@@ -44,7 +44,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend uncollapsed><span class="text">Authentication</span></legend>
|
||||
<legend><span class="text">Authentication</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-sm-2 control-label" for="smtpAuth">Enable Authentication</label>
|
||||
<div class="col-sm-4">
|
||||
@@ -65,7 +65,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions">
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||
<button data-kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button data-kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
|
||||
@@ -1,76 +1,122 @@
|
||||
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||
<div id="content-area" class="col-sm-9" role="main">
|
||||
<data-kc-navigation data-kc-current="token" data-kc-realm="realm.realm" data-kc-social="realm.social"></data-kc-navigation>
|
||||
<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">Token</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Token Settings</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="tokenLifespan">Token lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.tokenLifespan"
|
||||
id="tokenLifespan" name="tokenLifespan"/>
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="tokenLifespanUnit" data-ng-model="realm.tokenLifespanUnit" >
|
||||
<option data-ng-selected="!realm.tokenLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accessCodeLifespan">Access code lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespan" id="accessCodeLifespan" name="accessCodeLifespan">
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="accessCodeLifespanUnit" data-ng-model="realm.accessCodeLifespanUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="accessCodeLifespanUserAction" class="two-lines">Access code user action lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction">
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="accessCodeLifespanUserActionUnit" data-ng-model="realm.accessCodeLifespanUserActionUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||
<div id="content-area" class="col-sm-9" role="main">
|
||||
<data-kc-navigation data-kc-current="token" data-kc-realm="realm.realm" data-kc-social="realm.social"></data-kc-navigation>
|
||||
<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">Token</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Token Settings</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="rememberMe">Remember Me</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-model="realm.rememberMe" name="rememberMe" id="rememberMe" onoffswitch />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="centralLoginLifespan">Central Login Lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.centralLoginLifespan"
|
||||
id="centralLoginLifespan" name="centralLoginLifespan"/>
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="centralLoginLifespanUnit" data-ng-model="realm.centralLoginLifespanUnit" >
|
||||
<option data-ng-selected="!realm.centralLoginLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="accessTokenLifespan">Access Token Lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.accessTokenLifespan"
|
||||
id="accessTokenLifespan" name="accessTokenLifespan"/>
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="accessTokenLifespanUnit" data-ng-model="realm.accessTokenLifespanUnit" >
|
||||
<option data-ng-selected="!realm.accessTokenLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="accessCodeLifespan">Access code lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespan" id="accessCodeLifespan" name="accessCodeLifespan">
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="accessCodeLifespanUnit" data-ng-model="realm.accessCodeLifespanUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="accessCodeLifespanUserAction" class="two-lines">Access code user action lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1" max="31536000" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction">
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="accessCodeLifespanUserActionUnit" data-ng-model="realm.accessCodeLifespanUserActionUnit">
|
||||
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label class="col-sm-2 control-label" for="refreshTokenLifespan">Refresh token lifespan</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control" type="number" required min="1"
|
||||
max="31536000" data-ng-model="realm.refreshTokenLifespan"
|
||||
id="refreshTokenLifespan" name="refreshTokenLifespan"/>
|
||||
</div>
|
||||
<div class="col-sm-2 select-kc">
|
||||
<select name="refreshTokenLifespanUnit" data-ng-model="realm.refreshTokenLifespanUnit" >
|
||||
<option data-ng-selected="!realm.refreshTokenLifespanUnit">Seconds</option>
|
||||
<option>Minutes</option>
|
||||
<option>Hours</option>
|
||||
<option>Days</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
</ol>
|
||||
<h2 data-ng-show="create"><span>{{realm.realm}}</span> Add Role</h2>
|
||||
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="name">Role name <span class="required" data-ng-show="create">*</span></label>
|
||||
@@ -96,7 +96,7 @@
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<div class="select-kc">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications" ng-disabled="false">
|
||||
<option value="" selected> Select an Application...</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -133,7 +133,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="!create">
|
||||
<div class="pull-right form-actions" data-ng-show="!create && access.manageRealm">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
|
||||
@@ -13,22 +13,18 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}">Add Role</a>
|
||||
<!-- <button class="remove disabled">Remove</button> -->
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="roles && roles.length > 5">
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="search-comp clearfix">
|
||||
<input type="text" placeholder="Search..." class="search">
|
||||
<button class="icon-search" tooltip-placement="right"
|
||||
tooltip="Search by role name.">
|
||||
<input type="text" placeholder="Search..." data-ng-model="searchQuery" class="form-control search">
|
||||
<button class="kc-icon-search" tooltip-placement="right"
|
||||
tooltip="Search by name.">
|
||||
Icon: search
|
||||
</button>
|
||||
</div>
|
||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}">Add Role</a>
|
||||
<!-- <button class="remove disabled">Remove</button> -->
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-ng-show="roles && roles.length > 0">
|
||||
@@ -37,20 +33,21 @@
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot data-ng-show="roles && roles.length > 5"> <!-- todo -->
|
||||
<!--
|
||||
<tfoot data-ng-show="roles && roles.length > 5">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="table-nav">
|
||||
<a href="#" class="first disabled">First page</a><a href="#" class="prev disabled">Previous
|
||||
page</a><span><strong>1-8</strong> of <strong>10</strong></span><a href="#"
|
||||
class="next">Next
|
||||
page</a><a href="#" class="last">Last page</a>
|
||||
<a href="#" class="first disabled">First page</a>
|
||||
<a href="#" class="prev disabled">Previous page</a><span><strong>1-8</strong> of <strong>10</strong></span>
|
||||
<a href="#" class="next">Next page</a><a href="#" class="last">Last page</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
-->
|
||||
<tbody>
|
||||
<tr ng-repeat="role in roles">
|
||||
<tr ng-repeat="role in roles | filter:{name: searchQuery}">
|
||||
<td><a href="#/realms/{{realm.realm}}/roles/{{role.name}}">{{role.name}}</a></td>
|
||||
<td>{{role.composite}}</td>
|
||||
<td>{{role.description}}</td>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="access.manageUsers"><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>
|
||||
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
@@ -13,7 +14,7 @@
|
||||
<li class="active">Role Mappings</li>
|
||||
</ol>
|
||||
<h2><span>{{user.username}}'s</span> Role Mappings</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
|
||||
|
||||
<fieldset>
|
||||
<legend><span class="text">Realm Roles</span> </legend>
|
||||
@@ -54,7 +55,7 @@
|
||||
<div class="col-sm-4">
|
||||
<div class="input-group">
|
||||
<div class="select-kc">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
|
||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications" ng-disabled="false">
|
||||
<option value="" selected> Select an Application...</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
|
||||
<li class="active">Realm Sessions</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> Sessions</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" ng-click="logoutAll()">Logout All</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Application</th>
|
||||
<th>Active Sessions</th>
|
||||
<th>Active Users</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="(application, data) in stats">
|
||||
<td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
|
||||
<td>{{data.activeSessions}}</td>
|
||||
<td>{{data.activeUsers}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
|
||||
<li class="active">Revocation</li>
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{realm.realm}}</span> Revocation Policies</h2>
|
||||
<form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageRealm">
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="notBefore">Not Before</label>
|
||||
<div class="col-sm-4">
|
||||
<input ng-disabled="true" class="form-control" type="text" id="notBefore" name="notBefore" data-ng-model="notBefore" autofocus>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="access.manageApplications">
|
||||
<button type="submit" data-ng-click="clear()" class="btn btn-default btn-lg">Clear
|
||||
</button>
|
||||
<button type="submit" data-ng-click="setNotBeforeNow()" class="btn btn-primary btn-lg">Set To Now
|
||||
</button>
|
||||
<button type="submit" data-ng-click="pushRevocation()" class="btn btn-primary btn-lg">Push
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,6 +5,7 @@
|
||||
<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>
|
||||
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||
<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 data-ng-show="access.manageUsers"><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>
|
||||
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="content">
|
||||
@@ -22,7 +23,7 @@
|
||||
</ol>
|
||||
<h2 data-ng-hide="create"><span>{{user.username}}'s</span> Attributes</h2>
|
||||
|
||||
<form class="form-horizontal" name="userForm" novalidate>
|
||||
<form class="form-horizontal" name="userForm" novalidate kc-read-only="!access.manageUsers">
|
||||
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
@@ -75,16 +76,18 @@
|
||||
<label class="col-sm-2 control-label" for="reqActions">Required User Actions</label>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input type="text" ui-select2="userReqActionsOptions" ng-model="userActions" id="reqActions"/>
|
||||
<select ui-select2 ng-model="user.requiredActions" data-placeholder="Select an action..." multiple>
|
||||
<option ng-repeat="action in userReqActionList" value="{{action.id}}">{{action.text}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="pull-right form-actions" data-ng-show="create">
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="pull-right form-actions" data-ng-show="!create">
|
||||
<div class="pull-right form-actions" data-ng-show="!create && access.manageUsers">
|
||||
<button kc-reset data-ng-show="changed">Clear changes</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
|
||||
</ul>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<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">User Sessions</li>
|
||||
</ol>
|
||||
<h2><span>{{user.username}}</span> Sessions</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="kc-table-actions" colspan="3">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" ng-click="logoutAll()">Logout</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Application</th>
|
||||
<th>Login Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="(application, data) in stats">
|
||||
<td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
|
||||
<td>{{data.whenLoggedIn | date:'medium'}}</td>
|
||||
<td><a ng-click="logoutApplication(application)">invalidate session</a> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
File renamed without changes.
@@ -1,10 +1,10 @@
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<li ng-class="{active: kcCurrent == 'general'}"><a href="#/realms/{{kcRealm}}">General</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'social'}" data-ng-show="kcSocial"><a href="#/realms/{{kcRealm}}/social-settings">Social</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'roles'}"><a href="#/realms/{{kcRealm}}/roles">Roles</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'defRoles'}"><a href="#/realms/{{kcRealm}}/default-roles">Default Roles</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'credentials'}"><a href="#/realms/{{kcRealm}}/required-credentials">Credentials</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'token'}"><a href="#/realms/{{kcRealm}}/token-settings">Token</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'keys'}"><a href="#/realms/{{kcRealm}}/keys-settings">Keys</a></li>
|
||||
<li ng-class="{active: kcCurrent == 'email'}"><a href="#/realms/{{kcRealm}}/smtp-settings">Email</a></li>
|
||||
</ul>
|
||||
<li ng-class="{active: !path[2]}"><a href="#/realms/{{realm.realm}}">General</a></li>
|
||||
<li ng-class="{active: path[2] == 'social'}" data-ng-show="realm.social && access.viewRealm"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
|
||||
<li ng-class="{active: path[2] == 'roles'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
|
||||
<li ng-class="{active: path[2] == 'default-roles'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
|
||||
<li ng-class="{active: path[2] == 'required-credentials'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
|
||||
<li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
|
||||
<li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
|
||||
<li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,12 @@
|
||||
<span>
|
||||
<div class='onoffswitch' tabindex='0'>
|
||||
<input type='checkbox' ng-model='ngModel' class='onoffswitch-checkbox' name='{{name}}' id='{{id}}'>
|
||||
<label for='{{id}}' class='onoffswitch-label'>
|
||||
<span class='onoffswitch-inner'>
|
||||
<span class='onoffswitch-active'>{{kcOnText}}</span>
|
||||
<span class='onoffswitch-inactive'>{{kcOffText}}</span>
|
||||
</span>
|
||||
<span class='onoffswitch-switch'></span>
|
||||
</label>
|
||||
</div>
|
||||
</span>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-alpha-2</version>
|
||||
<version>1.0-alpha-3</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -18,11 +18,11 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
|
||||
protected ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public SkeletonKeyContextResolver() {
|
||||
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
|
||||
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
|
||||
}
|
||||
|
||||
public SkeletonKeyContextResolver(boolean indent) {
|
||||
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
|
||||
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
|
||||
if (indent) {
|
||||
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-alpha-2</version>
|
||||
<version>1.0-alpha-3</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -15,13 +15,14 @@ public class AbstractOAuthClient {
|
||||
public static final String OAUTH_TOKEN_REQUEST_STATE = "OAuth_Token_Request_State";
|
||||
protected String clientId;
|
||||
protected Map<String, String> credentials;
|
||||
protected KeyStore truststore;
|
||||
protected String authUrl;
|
||||
protected String codeUrl;
|
||||
protected String refreshUrl;
|
||||
protected String scope;
|
||||
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
|
||||
protected String stateCookiePath;
|
||||
protected boolean isSecure;
|
||||
protected boolean publicClient;
|
||||
protected final AtomicLong counter = new AtomicLong();
|
||||
|
||||
protected String getStateCode() {
|
||||
@@ -44,20 +45,10 @@ public class AbstractOAuthClient {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public KeyStore getTruststore() {
|
||||
return truststore;
|
||||
}
|
||||
|
||||
public void setTruststore(KeyStore truststore) {
|
||||
this.truststore = truststore;
|
||||
}
|
||||
|
||||
public String getAuthUrl() {
|
||||
return authUrl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setAuthUrl(String authUrl) {
|
||||
this.authUrl = authUrl;
|
||||
}
|
||||
@@ -70,6 +61,14 @@ public class AbstractOAuthClient {
|
||||
this.codeUrl = codeUrl;
|
||||
}
|
||||
|
||||
public String getRefreshUrl() {
|
||||
return refreshUrl;
|
||||
}
|
||||
|
||||
public void setRefreshUrl(String refreshUrl) {
|
||||
this.refreshUrl = refreshUrl;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
@@ -94,6 +93,14 @@ public class AbstractOAuthClient {
|
||||
this.stateCookiePath = stateCookiePath;
|
||||
}
|
||||
|
||||
public boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
public void setPublicClient(boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
protected String stripOauthParametersFromRedirect(String uri) {
|
||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
||||
.replaceQueryParam("code", null)
|
||||
|
||||
+4
-3
@@ -1,16 +1,17 @@
|
||||
package org.keycloak;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SkeletonKeyPrincipal implements Principal {
|
||||
public class KeycloakPrincipal implements Principal, Serializable {
|
||||
protected String name;
|
||||
protected String surrogate;
|
||||
|
||||
public SkeletonKeyPrincipal(String name, String surrogate) {
|
||||
public KeycloakPrincipal(String name, String surrogate) {
|
||||
this.name = name;
|
||||
this.surrogate = surrogate;
|
||||
}
|
||||
@@ -29,7 +30,7 @@ public class SkeletonKeyPrincipal implements Principal {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
SkeletonKeyPrincipal that = (SkeletonKeyPrincipal) o;
|
||||
KeycloakPrincipal that = (KeycloakPrincipal) o;
|
||||
|
||||
if (!name.equals(that.name)) return false;
|
||||
if (surrogate != null ? !surrogate.equals(that.surrogate) : that.surrogate != null) return false;
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.keycloak;
|
||||
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakSecurityContext implements Serializable {
|
||||
protected String tokenString;
|
||||
protected AccessToken token;
|
||||
protected IDToken idToken;
|
||||
protected String idTokenString;
|
||||
|
||||
public KeycloakSecurityContext() {
|
||||
}
|
||||
|
||||
public KeycloakSecurityContext(String tokenString, AccessToken token, String idTokenString, IDToken idToken) {
|
||||
this.tokenString = tokenString;
|
||||
this.token = token;
|
||||
this.idToken = idToken;
|
||||
this.idTokenString = idTokenString;
|
||||
}
|
||||
|
||||
public AccessToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getTokenString() {
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
public IDToken getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
||||
public String getIdTokenString() {
|
||||
return idTokenString;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.keycloak;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OAuthErrorException extends Exception {
|
||||
public static final String INVALID_REQUEST = "invalid_request";
|
||||
public static final String INVALID_CLIENT = "invalid_client";
|
||||
public static final String INVALID_GRANT = "invalid_grant";
|
||||
public static final String INVALID_SCOPE = "invalid_grant";
|
||||
public static final String UNAUTHORIZED_CLIENT = "unauthorized_client";
|
||||
public static final String UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type";
|
||||
|
||||
public OAuthErrorException(String error, String description, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.error = error;
|
||||
this.description = description;
|
||||
}
|
||||
public OAuthErrorException(String error, String description, String message) {
|
||||
super(message);
|
||||
}
|
||||
public OAuthErrorException(String error, String description) {
|
||||
super(description);
|
||||
this.error = error;
|
||||
this.description = description;
|
||||
}
|
||||
public OAuthErrorException(String error, String description, Throwable cause) {
|
||||
super(description, cause);
|
||||
this.error = error;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public OAuthErrorException(String error) {
|
||||
super(error);
|
||||
this.error = error;
|
||||
}
|
||||
public OAuthErrorException(String error, Throwable cause) {
|
||||
super(error, cause);
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
|
||||
protected String error;
|
||||
protected String description;
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package org.keycloak;
|
||||
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
@@ -12,8 +12,12 @@ import java.security.PublicKey;
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RSATokenVerifier {
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException {
|
||||
return verifyToken(tokenString, realmKey, realm, true);
|
||||
}
|
||||
|
||||
public static SkeletonKeyToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException {
|
||||
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realm, boolean checkActive) throws VerificationException {
|
||||
JWSInput input = new JWSInput(tokenString);
|
||||
boolean verified = false;
|
||||
try {
|
||||
@@ -23,15 +27,12 @@ public class RSATokenVerifier {
|
||||
}
|
||||
if (!verified) throw new VerificationException("Token signature not validated");
|
||||
|
||||
SkeletonKeyToken token = null;
|
||||
AccessToken token = null;
|
||||
try {
|
||||
token = input.readJsonContent(SkeletonKeyToken.class);
|
||||
token = input.readJsonContent(AccessToken.class);
|
||||
} catch (IOException e) {
|
||||
throw new VerificationException(e);
|
||||
}
|
||||
if (!token.isActive()) {
|
||||
throw new VerificationException("Token is not active.");
|
||||
}
|
||||
String user = token.getSubject();
|
||||
if (user == null) {
|
||||
throw new VerificationException("Token user was null");
|
||||
@@ -40,6 +41,10 @@ public class RSATokenVerifier {
|
||||
throw new VerificationException("Token audience doesn't match domain");
|
||||
|
||||
}
|
||||
if (checkActive && !token.isActive()) {
|
||||
throw new VerificationException("Token is not active.");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,5 @@ 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";
|
||||
public static final String TOKEN_SERVICE_REFRESH_PATH = "/rest/realms/{realm-name}/tokens/refresh";
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package org.keycloak;
|
||||
|
||||
import org.keycloak.adapters.ResourceMetadata;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SkeletonKeySession implements Serializable {
|
||||
protected String tokenString;
|
||||
protected SkeletonKeyToken token;
|
||||
protected transient ResourceMetadata metadata;
|
||||
|
||||
public SkeletonKeySession() {
|
||||
}
|
||||
|
||||
public SkeletonKeySession(String tokenString, SkeletonKeyToken token, ResourceMetadata metadata) {
|
||||
this.tokenString = tokenString;
|
||||
this.token = token;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public SkeletonKeyToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getTokenString() {
|
||||
return tokenString;
|
||||
}
|
||||
|
||||
public ResourceMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,9 @@ public interface AdapterConstants {
|
||||
|
||||
// URL endpoints
|
||||
public static final String K_LOGOUT = "k_logout";
|
||||
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
|
||||
public static final String K_GET_USER_STATS = "k_get_user_stats";
|
||||
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
|
||||
public static final String K_QUERY_BEARER_TOKEN = "k_query_bearer_token";
|
||||
|
||||
// This param name is defined again in Keycloak Subsystem class
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.security.PublicKey;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ResourceMetadata {
|
||||
protected String realm;
|
||||
protected String resourceName;
|
||||
protected KeyStore clientKeystore;
|
||||
protected String clientKeyPassword;
|
||||
protected KeyStore truststore;
|
||||
protected PublicKey realmKey;
|
||||
protected String scope;
|
||||
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* keystore that contains service's private key and certificate.
|
||||
* Used when making invocations on remote HTTPS endpoints that require client-cert authentication
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public KeyStore getClientKeystore() {
|
||||
return clientKeystore;
|
||||
}
|
||||
|
||||
public String getClientKeyPassword() {
|
||||
return clientKeyPassword;
|
||||
}
|
||||
|
||||
public void setClientKeyPassword(String clientKeyPassword) {
|
||||
this.clientKeyPassword = clientKeyPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truststore to use if this service makes client invocations on remote HTTPS endpoints.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public KeyStore getTruststore() {
|
||||
return truststore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public key of the realm. Used to verify access tokens
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PublicKey getRealmKey() {
|
||||
return realmKey;
|
||||
}
|
||||
|
||||
public void setResourceName(String resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
public void setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public void setClientKeystore(KeyStore clientKeystore) {
|
||||
this.clientKeystore = clientKeystore;
|
||||
}
|
||||
|
||||
public void setTruststore(KeyStore truststore) {
|
||||
this.truststore = truststore;
|
||||
}
|
||||
|
||||
public void setRealmKey(PublicKey realmKey) {
|
||||
this.realmKey = realmKey;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
+45
-34
@@ -12,13 +12,26 @@ import java.util.Set;
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SkeletonKeyToken extends JsonWebToken {
|
||||
public class AccessToken extends IDToken {
|
||||
public static class Access {
|
||||
@JsonProperty("roles")
|
||||
protected Set<String> roles;
|
||||
@JsonProperty("verify_caller")
|
||||
protected Boolean verifyCaller;
|
||||
|
||||
public Access() {
|
||||
}
|
||||
|
||||
public Access clone() {
|
||||
Access access = new Access();
|
||||
access.verifyCaller = verifyCaller;
|
||||
if (roles != null) {
|
||||
access.roles = new HashSet<String>();
|
||||
access.roles.addAll(roles);
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
public Set<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
@@ -50,9 +63,6 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonProperty("issuedFor")
|
||||
public String issuedFor;
|
||||
|
||||
@JsonProperty("trusted-certs")
|
||||
protected Set<String> trustedCertificates;
|
||||
|
||||
@@ -69,6 +79,13 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||
return resourceAccess;
|
||||
}
|
||||
|
||||
public void setResourceAccess(Map<String, Access> resourceAccess) {
|
||||
this.resourceAccess = resourceAccess;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Does the realm require verifying the caller?
|
||||
*
|
||||
@@ -106,43 +123,44 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken id(String id) {
|
||||
return (SkeletonKeyToken) super.id(id);
|
||||
public AccessToken id(String id) {
|
||||
return (AccessToken) super.id(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken expiration(long expiration) {
|
||||
return (SkeletonKeyToken) super.expiration(expiration);
|
||||
public AccessToken expiration(long expiration) {
|
||||
return (AccessToken) super.expiration(expiration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken notBefore(long notBefore) {
|
||||
return (SkeletonKeyToken) super.notBefore(notBefore);
|
||||
public AccessToken notBefore(long notBefore) {
|
||||
return (AccessToken) super.notBefore(notBefore);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AccessToken issuedAt(int issuedAt) {
|
||||
return (AccessToken) super.issuedAt(issuedAt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken issuedAt(long issuedAt) {
|
||||
return (SkeletonKeyToken) super.issuedAt(issuedAt);
|
||||
public AccessToken issuer(String issuer) {
|
||||
return (AccessToken) super.issuer(issuer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken issuer(String issuer) {
|
||||
return (SkeletonKeyToken) super.issuer(issuer);
|
||||
public AccessToken audience(String audience) {
|
||||
return (AccessToken) super.audience(audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken audience(String audience) {
|
||||
return (SkeletonKeyToken) super.audience(audience);
|
||||
public AccessToken subject(String subject) {
|
||||
return (AccessToken) super.subject(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken principal(String principal) {
|
||||
return (SkeletonKeyToken) super.principal(principal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkeletonKeyToken type(String type) {
|
||||
return (SkeletonKeyToken) super.type(type);
|
||||
public AccessToken type(String type) {
|
||||
return (AccessToken) super.type(type);
|
||||
}
|
||||
|
||||
public Set<String> getAllowedOrigins() {
|
||||
@@ -169,17 +187,10 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||
this.trustedCertificates = trustedCertificates;
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth client the token was issued for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getIssuedFor() {
|
||||
return issuedFor;
|
||||
@Override
|
||||
public AccessToken issuedFor(String issuedFor) {
|
||||
return (AccessToken)super.issuedFor(issuedFor);
|
||||
}
|
||||
|
||||
public SkeletonKeyToken issuedFor(String issuedFor) {
|
||||
this.issuedFor = issuedFor;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,6 +21,12 @@ public class AccessTokenResponse {
|
||||
@JsonProperty("token_type")
|
||||
protected String tokenType;
|
||||
|
||||
@JsonProperty("id_token")
|
||||
protected String idToken;
|
||||
|
||||
@JsonProperty("not-before-policy")
|
||||
protected int notBeforePolicy;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
@@ -52,4 +58,20 @@ public class AccessTokenResponse {
|
||||
public void setTokenType(String tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
public String getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
||||
public void setIdToken(String idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
public int getNotBeforePolicy() {
|
||||
return notBeforePolicy;
|
||||
}
|
||||
|
||||
public void setNotBeforePolicy(int notBeforePolicy) {
|
||||
this.notBeforePolicy = notBeforePolicy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package org.keycloak.representations;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class IDToken extends JsonWebToken {
|
||||
@JsonProperty("nonce")
|
||||
protected String nonce;
|
||||
|
||||
@JsonProperty("name")
|
||||
protected String name;
|
||||
|
||||
@JsonProperty("given_name")
|
||||
protected String givenName;
|
||||
|
||||
@JsonProperty("family_name")
|
||||
protected String familyName;
|
||||
|
||||
@JsonProperty("middle_name")
|
||||
protected String middleName;
|
||||
|
||||
@JsonProperty("nickname")
|
||||
protected String nickName;
|
||||
|
||||
@JsonProperty("preferred_username")
|
||||
protected String preferredUsername;
|
||||
|
||||
@JsonProperty("profile")
|
||||
protected String profile;
|
||||
|
||||
@JsonProperty("picture")
|
||||
protected String picture;
|
||||
|
||||
@JsonProperty("website")
|
||||
protected String website;
|
||||
|
||||
@JsonProperty("email")
|
||||
protected String email;
|
||||
|
||||
@JsonProperty("email_verified")
|
||||
protected Boolean emailVerified;
|
||||
|
||||
@JsonProperty("gender")
|
||||
protected String gender;
|
||||
|
||||
@JsonProperty("birthdate")
|
||||
protected String birthdate;
|
||||
|
||||
@JsonProperty("zoneinfo")
|
||||
protected String zoneinfo;
|
||||
|
||||
@JsonProperty("locale")
|
||||
protected String locale;
|
||||
|
||||
@JsonProperty("phone_number")
|
||||
protected String phoneNumber;
|
||||
|
||||
@JsonProperty("phone_number_verified")
|
||||
protected Boolean phoneNumberVerified;
|
||||
|
||||
@JsonProperty("address")
|
||||
protected String address;
|
||||
|
||||
@JsonProperty("updated_at")
|
||||
protected Long updatedAt;
|
||||
|
||||
@JsonProperty("formatted")
|
||||
protected String formattedAddress;
|
||||
|
||||
@JsonProperty("street_address")
|
||||
protected String streetAddress;
|
||||
|
||||
@JsonProperty("locality")
|
||||
protected String locality;
|
||||
|
||||
@JsonProperty("region")
|
||||
protected String region;
|
||||
|
||||
@JsonProperty("postal_code")
|
||||
protected String postalCode;
|
||||
|
||||
@JsonProperty("country")
|
||||
protected String country;
|
||||
|
||||
@JsonProperty("claims_locales")
|
||||
protected String claimsLocales;
|
||||
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
public void setNonce(String nonce) {
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getGivenName() {
|
||||
return givenName;
|
||||
}
|
||||
|
||||
public void setGivenName(String givenName) {
|
||||
this.givenName = givenName;
|
||||
}
|
||||
|
||||
public String getFamilyName() {
|
||||
return familyName;
|
||||
}
|
||||
|
||||
public void setFamilyName(String familyName) {
|
||||
this.familyName = familyName;
|
||||
}
|
||||
|
||||
public String getMiddleName() {
|
||||
return middleName;
|
||||
}
|
||||
|
||||
public void setMiddleName(String middleName) {
|
||||
this.middleName = middleName;
|
||||
}
|
||||
|
||||
public String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
|
||||
public void setNickName(String nickName) {
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public String getPreferredUsername() {
|
||||
return preferredUsername;
|
||||
}
|
||||
|
||||
public void setPreferredUsername(String preferredUsername) {
|
||||
this.preferredUsername = preferredUsername;
|
||||
}
|
||||
|
||||
public String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(String profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
public String getPicture() {
|
||||
return picture;
|
||||
}
|
||||
|
||||
public void setPicture(String picture) {
|
||||
this.picture = picture;
|
||||
}
|
||||
|
||||
public String getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setWebsite(String website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean getEmailVerified() {
|
||||
return emailVerified;
|
||||
}
|
||||
|
||||
public void setEmailVerified(Boolean emailVerified) {
|
||||
this.emailVerified = emailVerified;
|
||||
}
|
||||
|
||||
public String getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(String gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public String getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
|
||||
public void setBirthdate(String birthdate) {
|
||||
this.birthdate = birthdate;
|
||||
}
|
||||
|
||||
public String getZoneinfo() {
|
||||
return zoneinfo;
|
||||
}
|
||||
|
||||
public void setZoneinfo(String zoneinfo) {
|
||||
this.zoneinfo = zoneinfo;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
|
||||
public void setPhoneNumber(String phoneNumber) {
|
||||
this.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
public Boolean getPhoneNumberVerified() {
|
||||
return phoneNumberVerified;
|
||||
}
|
||||
|
||||
public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
|
||||
this.phoneNumberVerified = phoneNumberVerified;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Long getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(Long updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public String getFormattedAddress() {
|
||||
return formattedAddress;
|
||||
}
|
||||
|
||||
public void setFormattedAddress(String formattedAddress) {
|
||||
this.formattedAddress = formattedAddress;
|
||||
}
|
||||
|
||||
public String getStreetAddress() {
|
||||
return streetAddress;
|
||||
}
|
||||
|
||||
public void setStreetAddress(String streetAddress) {
|
||||
this.streetAddress = streetAddress;
|
||||
}
|
||||
|
||||
public String getLocality() {
|
||||
return locality;
|
||||
}
|
||||
|
||||
public void setLocality(String locality) {
|
||||
this.locality = locality;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public void setRegion(String region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
public void setPostalCode(String postalCode) {
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public String getClaimsLocales() {
|
||||
return claimsLocales;
|
||||
}
|
||||
|
||||
public void setClaimsLocales(String claimsLocales) {
|
||||
this.claimsLocales = claimsLocales;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class JsonWebToken implements Serializable {
|
||||
@JsonProperty("nbf")
|
||||
protected long notBefore;
|
||||
@JsonProperty("iat")
|
||||
protected long issuedAt;
|
||||
protected int issuedAt;
|
||||
@JsonProperty("iss")
|
||||
protected String issuer;
|
||||
@JsonProperty("aud")
|
||||
@@ -26,6 +26,8 @@ public class JsonWebToken implements Serializable {
|
||||
protected String subject;
|
||||
@JsonProperty("typ")
|
||||
protected String type;
|
||||
@JsonProperty("azp")
|
||||
public String issuedFor;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -78,7 +80,7 @@ public class JsonWebToken implements Serializable {
|
||||
return (!isExpired() || expiration == 0) && (isNotBefore() || notBefore == 0);
|
||||
}
|
||||
|
||||
public long getIssuedAt() {
|
||||
public int getIssuedAt() {
|
||||
return issuedAt;
|
||||
}
|
||||
|
||||
@@ -87,11 +89,11 @@ public class JsonWebToken implements Serializable {
|
||||
*/
|
||||
@JsonIgnore
|
||||
public JsonWebToken issuedNow() {
|
||||
issuedAt = System.currentTimeMillis() / 1000;
|
||||
issuedAt = (int)(System.currentTimeMillis() / 1000);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JsonWebToken issuedAt(long issuedAt) {
|
||||
public JsonWebToken issuedAt(int issuedAt) {
|
||||
this.issuedAt = issuedAt;
|
||||
return this;
|
||||
}
|
||||
@@ -120,8 +122,8 @@ public class JsonWebToken implements Serializable {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public JsonWebToken principal(String principal) {
|
||||
this.subject = principal;
|
||||
public JsonWebToken subject(String subject) {
|
||||
this.subject = subject;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -133,4 +135,18 @@ public class JsonWebToken implements Serializable {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth client the token was issued for.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getIssuedFor() {
|
||||
return issuedFor;
|
||||
}
|
||||
|
||||
public JsonWebToken issuedFor(String issuedFor) {
|
||||
this.issuedFor = issuedFor;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.keycloak.representations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RefreshToken extends AccessToken {
|
||||
public RefreshToken() {
|
||||
type("REFRESH");
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep copies issuer, subject, issuedFor, realmAccess, and resourceAccess
|
||||
* from AccessToken.
|
||||
*
|
||||
* @param token
|
||||
*/
|
||||
public RefreshToken(AccessToken token) {
|
||||
this();
|
||||
this.issuer = token.issuer;
|
||||
this.subject = token.subject;
|
||||
this.issuedFor = token.issuedFor;
|
||||
if (token.realmAccess != null) {
|
||||
realmAccess = token.realmAccess.clone();
|
||||
}
|
||||
if (token.resourceAccess != null) {
|
||||
resourceAccess = new HashMap<String, Access>();
|
||||
for (Map.Entry<String, Access> entry : token.resourceAccess.entrySet()) {
|
||||
resourceAccess.put(entry.getKey(), entry.getValue().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.keycloak.representations;
|
||||
|
||||
|
||||
import org.keycloak.util.MultivaluedHashMap;
|
||||
|
||||
/**
|
||||
* Key is resource desired. Values are roles desired for that resource
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SkeletonKeyScope extends MultivaluedHashMap<String, String> {
|
||||
}
|
||||
@@ -8,18 +8,20 @@ import org.codehaus.jackson.annotate.JsonIgnore;
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AdminAction {
|
||||
public abstract class AdminAction {
|
||||
protected String id;
|
||||
protected long expiration;
|
||||
protected int expiration;
|
||||
protected String resource;
|
||||
protected String action;
|
||||
|
||||
public AdminAction() {
|
||||
}
|
||||
|
||||
public AdminAction(String id, long expiration, String resource) {
|
||||
public AdminAction(String id, int expiration, String resource, String action) {
|
||||
this.id = id;
|
||||
this.expiration = expiration;
|
||||
this.resource = resource;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@@ -36,11 +38,16 @@ public class AdminAction {
|
||||
return time > expiration;
|
||||
}
|
||||
|
||||
public long getExpiration() {
|
||||
/**
|
||||
* Time in seconds since epoc
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(long expiration) {
|
||||
public void setExpiration(int expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
@@ -51,4 +58,14 @@ public class AdminAction {
|
||||
public void setResource(String resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public abstract boolean validate();
|
||||
}
|
||||
@@ -5,13 +5,15 @@ package org.keycloak.representations.adapters.action;
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class LogoutAction extends AdminAction {
|
||||
public static final String LOGOUT = "LOGOUT";
|
||||
protected String user;
|
||||
protected int notBefore;
|
||||
|
||||
public LogoutAction() {
|
||||
}
|
||||
|
||||
public LogoutAction(String id, long expiration, String resource, String user) {
|
||||
super(id, expiration, resource);
|
||||
public LogoutAction(String id, int expiration, String resource, String user, int notBefore) {
|
||||
super(id, expiration, resource, LOGOUT);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@@ -22,4 +24,17 @@ public class LogoutAction extends AdminAction {
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public int getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(int notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
return LOGOUT.equals(action);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.keycloak.representations.adapters.action;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PushNotBeforeAction extends AdminAction {
|
||||
|
||||
public static final String PUSH_NOT_BEFORE = "PUSH_NOT_BEFORE";
|
||||
protected int notBefore;
|
||||
|
||||
public PushNotBeforeAction() {
|
||||
}
|
||||
|
||||
public PushNotBeforeAction(String id, int expiration, String resource, int notBefore) {
|
||||
super(id, expiration, resource, PUSH_NOT_BEFORE);
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
public int getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(int notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
return PUSH_NOT_BEFORE.equals(action);
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.keycloak.representations.adapters.action;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SessionStats {
|
||||
protected int activeSessions;
|
||||
protected int activeUsers;
|
||||
protected Map<String, UserStats> users;
|
||||
|
||||
public int getActiveSessions() {
|
||||
return activeSessions;
|
||||
}
|
||||
|
||||
public void setActiveSessions(int activeSessions) {
|
||||
this.activeSessions = activeSessions;
|
||||
}
|
||||
|
||||
public int getActiveUsers() {
|
||||
return activeUsers;
|
||||
}
|
||||
|
||||
public void setActiveUsers(int activeUsers) {
|
||||
this.activeUsers = activeUsers;
|
||||
}
|
||||
|
||||
public Map<String, UserStats> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(Map<String, UserStats> users) {
|
||||
this.users = users;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.keycloak.representations.adapters.action;
|
||||
|
||||
/**
|
||||
* Query session stats.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SessionStatsAction extends AdminAction {
|
||||
|
||||
public static final String SESSION_STATS = "SESSION_STATS";
|
||||
|
||||
protected boolean listUsers;
|
||||
|
||||
public SessionStatsAction() {
|
||||
}
|
||||
|
||||
public SessionStatsAction(String id, int expiration, String resource) {
|
||||
super(id, expiration, resource, SESSION_STATS);
|
||||
}
|
||||
|
||||
public boolean isListUsers() {
|
||||
return listUsers;
|
||||
}
|
||||
|
||||
public void setListUsers(boolean listUsers) {
|
||||
this.listUsers = listUsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
return SESSION_STATS.equals(action);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.keycloak.representations.adapters.action;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserStats {
|
||||
protected boolean loggedIn;
|
||||
protected long whenLoggedIn;
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return loggedIn;
|
||||
}
|
||||
|
||||
public void setLoggedIn(boolean loggedIn) {
|
||||
this.loggedIn = loggedIn;
|
||||
}
|
||||
|
||||
public long getWhenLoggedIn() {
|
||||
return whenLoggedIn;
|
||||
}
|
||||
|
||||
public void setWhenLoggedIn(long whenLoggedIn) {
|
||||
this.whenLoggedIn = whenLoggedIn;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.keycloak.representations.adapters.action;
|
||||
|
||||
/**
|
||||
* Query session stats.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserStatsAction extends AdminAction {
|
||||
|
||||
public static final String USER_STATS = "USER_STATS";
|
||||
protected String user;
|
||||
|
||||
public UserStatsAction() {
|
||||
}
|
||||
|
||||
public UserStatsAction(String id, int expiration, String resource, String user) {
|
||||
super(id, expiration, resource, USER_STATS);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() {
|
||||
return USER_STATS.equals(action);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
"resource", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
"expose-token", "bearer-only", "scope",
|
||||
"expose-token", "bearer-only",
|
||||
"connection-pool-size",
|
||||
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
|
||||
"client-keystore", "client-keystore-password", "client-key-password"
|
||||
|
||||
+8
-9
@@ -2,7 +2,6 @@ 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;
|
||||
@@ -14,10 +13,10 @@ import java.util.Map;
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||
"resource", "credentials",
|
||||
"resource", "public-client", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
"expose-token", "bearer-only", "scope"})
|
||||
"expose-token", "bearer-only"})
|
||||
public class BaseAdapterConfig extends BaseRealmConfig {
|
||||
@JsonProperty("resource")
|
||||
protected String resource;
|
||||
@@ -35,10 +34,10 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
||||
protected boolean exposeToken;
|
||||
@JsonProperty("bearer-only")
|
||||
protected boolean bearerOnly;
|
||||
@JsonProperty("public-client")
|
||||
protected boolean publicClient;
|
||||
@JsonProperty("credentials")
|
||||
protected Map<String, String> credentials = new HashMap<String, String>();
|
||||
@JsonProperty("scope")
|
||||
protected SkeletonKeyScope scope;
|
||||
|
||||
|
||||
public boolean isUseResourceRoleMappings() {
|
||||
@@ -113,11 +112,11 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public SkeletonKeyScope getScope() {
|
||||
return scope;
|
||||
public boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
public void setScope(SkeletonKeyScope scope) {
|
||||
this.scope = scope;
|
||||
public void setPublicClient(boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
}
|
||||
+48
-20
@@ -12,12 +12,17 @@ public class ApplicationRepresentation {
|
||||
protected String name;
|
||||
protected String adminUrl;
|
||||
protected String baseUrl;
|
||||
protected boolean surrogateAuthRequired;
|
||||
protected boolean enabled;
|
||||
protected List<CredentialRepresentation> credentials;
|
||||
protected Boolean surrogateAuthRequired;
|
||||
protected Boolean enabled;
|
||||
protected String secret;
|
||||
protected String[] defaultRoles;
|
||||
protected List<String> redirectUris;
|
||||
protected List<String> webOrigins;
|
||||
protected ClaimRepresentation claims;
|
||||
protected Integer notBefore;
|
||||
protected Boolean bearerOnly;
|
||||
protected Boolean publicClient;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -35,19 +40,19 @@ public class ApplicationRepresentation {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isSurrogateAuthRequired() {
|
||||
public Boolean isSurrogateAuthRequired() {
|
||||
return surrogateAuthRequired;
|
||||
}
|
||||
|
||||
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
|
||||
public void setSurrogateAuthRequired(Boolean surrogateAuthRequired) {
|
||||
this.surrogateAuthRequired = surrogateAuthRequired;
|
||||
}
|
||||
|
||||
@@ -67,21 +72,12 @@ public class ApplicationRepresentation {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public List<CredentialRepresentation> getCredentials() {
|
||||
return credentials;
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setCredentials(List<CredentialRepresentation> credentials) {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public ApplicationRepresentation credential(String type, String value) {
|
||||
if (this.credentials == null) credentials = new ArrayList<CredentialRepresentation>();
|
||||
CredentialRepresentation cred = new CredentialRepresentation();
|
||||
cred.setType(type);
|
||||
cred.setValue(value);
|
||||
credentials.add(cred);
|
||||
return this;
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public List<String> getRedirectUris() {
|
||||
@@ -107,4 +103,36 @@ public class ApplicationRepresentation {
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
|
||||
public ClaimRepresentation getClaims() {
|
||||
return claims;
|
||||
}
|
||||
|
||||
public void setClaims(ClaimRepresentation claims) {
|
||||
this.claims = claims;
|
||||
}
|
||||
|
||||
public Integer getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(Integer notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
public Boolean isBearerOnly() {
|
||||
return bearerOnly;
|
||||
}
|
||||
|
||||
public void setBearerOnly(Boolean bearerOnly) {
|
||||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
|
||||
public Boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
public void setPublicClient(Boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClaimRepresentation {
|
||||
protected boolean name;
|
||||
protected boolean username;
|
||||
protected boolean profile;
|
||||
protected boolean picture;
|
||||
protected boolean website;
|
||||
protected boolean email;
|
||||
protected boolean gender;
|
||||
protected boolean locale;
|
||||
protected boolean address;
|
||||
protected boolean phone;
|
||||
|
||||
public boolean getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(boolean name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(boolean username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public boolean getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(boolean profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
public boolean getPicture() {
|
||||
return picture;
|
||||
}
|
||||
|
||||
public void setPicture(boolean picture) {
|
||||
this.picture = picture;
|
||||
}
|
||||
|
||||
public boolean getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setWebsite(boolean website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public boolean getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(boolean email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public boolean getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(boolean gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public boolean getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(boolean locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public boolean getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(boolean address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public boolean getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(boolean phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,12 @@ public class OAuthClientRepresentation {
|
||||
protected String baseUrl;
|
||||
protected List<String> redirectUris;
|
||||
protected List<String> webOrigins;
|
||||
protected boolean enabled;
|
||||
protected List<CredentialRepresentation> credentials;
|
||||
protected Boolean enabled;
|
||||
protected String secret;
|
||||
protected ClaimRepresentation claims;
|
||||
protected Integer notBefore;
|
||||
protected Boolean publicClient;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -31,11 +35,11 @@ public class OAuthClientRepresentation {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
@@ -63,11 +67,35 @@ public class OAuthClientRepresentation {
|
||||
this.webOrigins = webOrigins;
|
||||
}
|
||||
|
||||
public List<CredentialRepresentation> getCredentials() {
|
||||
return credentials;
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setCredentials(List<CredentialRepresentation> credentials) {
|
||||
this.credentials = credentials;
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public ClaimRepresentation getClaims() {
|
||||
return claims;
|
||||
}
|
||||
|
||||
public void setClaims(ClaimRepresentation claims) {
|
||||
this.claims = claims;
|
||||
}
|
||||
|
||||
public Integer getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(Integer notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
|
||||
public Boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
||||
public void setPublicClient(Boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
}
|
||||
+24
-45
@@ -15,37 +15,25 @@ import java.security.PublicKey;
|
||||
*/
|
||||
public class PublishedRealmRepresentation {
|
||||
protected String realm;
|
||||
protected String self;
|
||||
|
||||
@JsonProperty("public_key")
|
||||
protected String publicKeyPem;
|
||||
|
||||
@JsonProperty("authorization")
|
||||
protected String authorizationUrl;
|
||||
@JsonProperty("token-service")
|
||||
protected String tokenServiceUrl;
|
||||
|
||||
@JsonProperty("codes")
|
||||
protected String codeUrl;
|
||||
@JsonProperty("account-service")
|
||||
protected String accountServiceUrl;
|
||||
|
||||
@JsonProperty("grants")
|
||||
protected String grantUrl;
|
||||
@JsonProperty("admin-api")
|
||||
protected String adminApiUrl;
|
||||
|
||||
@JsonProperty("identity-grants")
|
||||
protected String identityGrantUrl;
|
||||
|
||||
@JsonProperty("admin-role")
|
||||
protected String adminRole;
|
||||
@JsonProperty("tokens-not-before")
|
||||
protected int notBefore;
|
||||
|
||||
@JsonIgnore
|
||||
protected volatile transient PublicKey publicKey;
|
||||
|
||||
public String getAdminRole() {
|
||||
return adminRole;
|
||||
}
|
||||
|
||||
public void setAdminRole(String adminRole) {
|
||||
this.adminRole = adminRole;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
@@ -54,14 +42,6 @@ public class PublishedRealmRepresentation {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public String getSelf() {
|
||||
return self;
|
||||
}
|
||||
|
||||
public void setSelf(String self) {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public String getPublicKeyPem() {
|
||||
return publicKeyPem;
|
||||
}
|
||||
@@ -100,36 +80,35 @@ public class PublishedRealmRepresentation {
|
||||
this.publicKeyPem = PemUtils.removeBeginEnd(s);
|
||||
}
|
||||
|
||||
|
||||
public String getAuthorizationUrl() {
|
||||
return authorizationUrl;
|
||||
public String getTokenServiceUrl() {
|
||||
return tokenServiceUrl;
|
||||
}
|
||||
|
||||
public void setAuthorizationUrl(String authorizationUrl) {
|
||||
this.authorizationUrl = authorizationUrl;
|
||||
public void setTokenServiceUrl(String tokenServiceUrl) {
|
||||
this.tokenServiceUrl = tokenServiceUrl;
|
||||
}
|
||||
|
||||
public String getCodeUrl() {
|
||||
return codeUrl;
|
||||
public String getAccountServiceUrl() {
|
||||
return accountServiceUrl;
|
||||
}
|
||||
|
||||
public void setCodeUrl(String codeUrl) {
|
||||
this.codeUrl = codeUrl;
|
||||
public void setAccountServiceUrl(String accountServiceUrl) {
|
||||
this.accountServiceUrl = accountServiceUrl;
|
||||
}
|
||||
|
||||
public String getGrantUrl() {
|
||||
return grantUrl;
|
||||
public String getAdminApiUrl() {
|
||||
return adminApiUrl;
|
||||
}
|
||||
|
||||
public void setGrantUrl(String grantUrl) {
|
||||
this.grantUrl = grantUrl;
|
||||
public void setAdminApiUrl(String adminApiUrl) {
|
||||
this.adminApiUrl = adminApiUrl;
|
||||
}
|
||||
|
||||
public String getIdentityGrantUrl() {
|
||||
return identityGrantUrl;
|
||||
public int getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setIdentityGrantUrl(String identityGrantUrl) {
|
||||
this.identityGrantUrl = identityGrantUrl;
|
||||
public void setNotBefore(int notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,16 @@ public class RealmRepresentation {
|
||||
protected String self; // link
|
||||
protected String id;
|
||||
protected String realm;
|
||||
protected Integer tokenLifespan;
|
||||
protected Integer notBefore;
|
||||
protected Integer accessTokenLifespan;
|
||||
protected Integer refreshTokenLifespan;
|
||||
protected Integer centralLoginLifespan;
|
||||
protected Integer accessCodeLifespan;
|
||||
protected Integer accessCodeLifespanUserAction;
|
||||
protected Boolean enabled;
|
||||
protected Boolean sslNotRequired;
|
||||
protected Boolean registrationAllowed;
|
||||
protected Boolean rememberMe;
|
||||
protected Boolean verifyEmail;
|
||||
protected Boolean resetPasswordAllowed;
|
||||
protected Boolean social;
|
||||
@@ -114,12 +118,28 @@ public class RealmRepresentation {
|
||||
this.sslNotRequired = sslNotRequired;
|
||||
}
|
||||
|
||||
public Integer getTokenLifespan() {
|
||||
return tokenLifespan;
|
||||
public Integer getAccessTokenLifespan() {
|
||||
return accessTokenLifespan;
|
||||
}
|
||||
|
||||
public void setTokenLifespan(Integer tokenLifespan) {
|
||||
this.tokenLifespan = tokenLifespan;
|
||||
public void setAccessTokenLifespan(Integer accessTokenLifespan) {
|
||||
this.accessTokenLifespan = accessTokenLifespan;
|
||||
}
|
||||
|
||||
public Integer getRefreshTokenLifespan() {
|
||||
return refreshTokenLifespan;
|
||||
}
|
||||
|
||||
public Integer getCentralLoginLifespan() {
|
||||
return centralLoginLifespan;
|
||||
}
|
||||
|
||||
public void setCentralLoginLifespan(Integer centralLoginLifespan) {
|
||||
this.centralLoginLifespan = centralLoginLifespan;
|
||||
}
|
||||
|
||||
public void setRefreshTokenLifespan(Integer refreshTokenLifespan) {
|
||||
this.refreshTokenLifespan = refreshTokenLifespan;
|
||||
}
|
||||
|
||||
public List<UserRoleMappingRepresentation> getRoleMappings() {
|
||||
@@ -140,7 +160,7 @@ public class RealmRepresentation {
|
||||
|
||||
public ScopeMappingRepresentation scopeMapping(String username) {
|
||||
ScopeMappingRepresentation mapping = new ScopeMappingRepresentation();
|
||||
mapping.setUsername(username);
|
||||
mapping.setClient(username);
|
||||
if (scopeMappings == null) scopeMappings = new ArrayList<ScopeMappingRepresentation>();
|
||||
scopeMappings.add(mapping);
|
||||
return mapping;
|
||||
@@ -222,6 +242,14 @@ public class RealmRepresentation {
|
||||
this.registrationAllowed = registrationAllowed;
|
||||
}
|
||||
|
||||
public Boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(Boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public Boolean isVerifyEmail() {
|
||||
return verifyEmail;
|
||||
}
|
||||
@@ -317,4 +345,12 @@ public class RealmRepresentation {
|
||||
public void setAccountTheme(String accountTheme) {
|
||||
this.accountTheme = accountTheme;
|
||||
}
|
||||
|
||||
public Integer getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(Integer notBefore) {
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class ScopeMappingRepresentation {
|
||||
protected String self; // link
|
||||
protected String username;
|
||||
protected String client;
|
||||
protected Set<String> roles;
|
||||
|
||||
public String getSelf() {
|
||||
@@ -20,12 +20,12 @@ public class ScopeMappingRepresentation {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
public String getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
public void setClient(String client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public Set<String> getRoles() {
|
||||
|
||||
@@ -6,6 +6,7 @@ package org.keycloak.representations.idm;
|
||||
public class SocialLinkRepresentation {
|
||||
|
||||
protected String socialProvider;
|
||||
protected String socialUserId;
|
||||
protected String socialUsername;
|
||||
|
||||
public String getSocialProvider() {
|
||||
@@ -16,6 +17,14 @@ public class SocialLinkRepresentation {
|
||||
this.socialProvider = socialProvider;
|
||||
}
|
||||
|
||||
public String getSocialUserId() {
|
||||
return socialUserId;
|
||||
}
|
||||
|
||||
public void setSocialUserId(String socialUserId) {
|
||||
this.socialUserId = socialUserId;
|
||||
}
|
||||
|
||||
public String getSocialUsername() {
|
||||
return socialUsername;
|
||||
}
|
||||
|
||||
+2
-1
@@ -32,9 +32,10 @@ public class SocialMappingRepresentation {
|
||||
return socialLinks;
|
||||
}
|
||||
|
||||
public SocialLinkRepresentation socialLink(String socialProvider, String socialUsername) {
|
||||
public SocialLinkRepresentation socialLink(String socialProvider, String socialUserId, String socialUsername) {
|
||||
SocialLinkRepresentation link = new SocialLinkRepresentation();
|
||||
link.setSocialProvider(socialProvider);
|
||||
link.setSocialUserId(socialUserId);
|
||||
link.setSocialUsername(socialUsername);
|
||||
if (socialLinks == null) socialLinks = new ArrayList<SocialLinkRepresentation>();
|
||||
socialLinks.add(link);
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.Map;
|
||||
public class UserRepresentation {
|
||||
|
||||
protected String self; // link
|
||||
protected String id;
|
||||
protected String username;
|
||||
protected boolean enabled;
|
||||
protected boolean totp;
|
||||
@@ -31,6 +32,14 @@ public class UserRepresentation {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.keycloak.util;
|
||||
|
||||
import net.iharder.Base64;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class BasicAuthHelper
|
||||
{
|
||||
public static String createHeader(String username, String password)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer(username);
|
||||
buf.append(':').append(password);
|
||||
try
|
||||
{
|
||||
return "Basic " + Base64.encodeBytes(buf.toString().getBytes("UTF-8"));
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] parseHeader(String header)
|
||||
{
|
||||
if (header.length() < 6) return null;
|
||||
String type = header.substring(0, 5);
|
||||
type = type.toLowerCase();
|
||||
if (!type.equalsIgnoreCase("Basic")) return null;
|
||||
String val = header.substring(6);
|
||||
try {
|
||||
val = new String(Base64.decode(val.getBytes()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String[] split = val.split(":");
|
||||
if (split.length != 2) return null;
|
||||
return split;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.codehaus.jackson.map.annotate.JsonSerialize;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Utility class to handle simple JSON serializable for Keycloak.
|
||||
@@ -18,13 +19,16 @@ public class JsonSerialization {
|
||||
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 void writeValueToStream(OutputStream os, Object obj) throws IOException {
|
||||
mapper.writeValue(os, obj);
|
||||
|
||||
}
|
||||
|
||||
public static String writeValueAsString(Object obj) throws IOException {
|
||||
return mapper.writeValueAsString(obj);
|
||||
}
|
||||
|
||||
Loaded 100 of 480 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user