nasty merge
|
@ -43,7 +43,34 @@ body {
|
|||
background-image: url(img/feedback-info-sign.png);
|
||||
background-color: #e4f3fa;
|
||||
}
|
||||
#idletimeout {
|
||||
background: #CC5100;
|
||||
color: #FFFFFF;
|
||||
font-size: 1.1em;
|
||||
padding: 0.90909090909091em;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
#idletimeout a {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.loading span {
|
||||
background: url(img/loader.gif) no-repeat center top;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -2.27272727272727em;
|
||||
margin-left: -2.27272727272727em;
|
||||
padding-top: 2.90909090909091em;
|
||||
font-size: 1.1em;
|
||||
color: #666;
|
||||
}
|
||||
/* Header */
|
||||
.header.rcue {
|
||||
z-index: 50;
|
||||
}
|
||||
.header.rcue .navbar.utility {
|
||||
background-color: #393F45;
|
||||
border-bottom: 1px solid #53565B;
|
||||
|
@ -65,36 +92,6 @@ body {
|
|||
min-height: 42px;
|
||||
max-width: 1170px;
|
||||
}
|
||||
.header.rcue .navbar.primary .select-rcue {
|
||||
font-size: 0.76923076923077em;
|
||||
margin-left: 1em;
|
||||
margin-top: 0.7em;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-color: #555a5e;
|
||||
background-image: none;
|
||||
background-image: url(img/sprite-arrow-down.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right -26px;
|
||||
border: 1px solid #676c6e;
|
||||
border-radius: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
.header.rcue .navbar.primary .select-rcue:hover {
|
||||
border-color: #7e8385;
|
||||
}
|
||||
.header.rcue .navbar.primary .select-rcue select {
|
||||
color: #fff;
|
||||
}
|
||||
.header.rcue .navbar.primary .select-rcue select:-moz-focusring {
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 #fff;
|
||||
}
|
||||
.header.rcue .navbar.primary .select-rcue select option {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
padding: 0.36363636363636em 0.90909090909091em;
|
||||
}
|
||||
.header.rcue .navbar.primary .nav > li {
|
||||
/*
|
||||
.dropdown {
|
||||
|
@ -215,7 +212,6 @@ body {
|
|||
.header.rcue .navbar.primary .nav > li .select-rcue select option {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
padding: 0.36363636363636em 0.90909090909091em;
|
||||
}
|
||||
.header.rcue .navbar.primary .nav > li a#refresh {
|
||||
border: none;
|
||||
|
@ -469,6 +465,42 @@ table + .feedback.inline.warning {
|
|||
td.token-cell button {
|
||||
margin-top: -1px;
|
||||
}
|
||||
/* Modal boxes */
|
||||
.modal .modal-dialog {
|
||||
padding-top: 10em;
|
||||
}
|
||||
.modal .modal-content {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
.modal .modal-header {
|
||||
background-color: #f8f8f8;
|
||||
padding: 1.5em 2em;
|
||||
border-bottom: none;
|
||||
}
|
||||
.modal .modal-header h3 {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
margin: 0;
|
||||
}
|
||||
.modal .modal-body p {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.modal .modal-body p.primary {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.45454545454545em;
|
||||
}
|
||||
.modal .modal-footer {
|
||||
border-top: 0;
|
||||
}
|
||||
.modal .modal-footer .primary,
|
||||
.modal .modal-footer .destructive {
|
||||
float: right;
|
||||
margin-left: 0.90909090909091em;
|
||||
}
|
||||
/* Page: User Account */
|
||||
.user form fieldset div:first-child {
|
||||
margin-top: 1em;
|
||||
|
|
|
@ -60,11 +60,43 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
#idletimeout {
|
||||
background: #CC5100;
|
||||
color: #FFFFFF;
|
||||
font-size: 1.1em;
|
||||
padding: 0.90909090909091em;
|
||||
text-align: center;
|
||||
display: none;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
|
||||
span {
|
||||
background: url(img/loader.gif) no-repeat center top;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -2.27272727272727em;
|
||||
margin-left: -2.27272727272727em;
|
||||
padding-top: 2.90909090909091em;
|
||||
font-size: 1.1em;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Header */
|
||||
|
||||
.header.rcue {
|
||||
|
||||
z-index: 50;
|
||||
|
||||
.navbar.utility {
|
||||
background-color: #393F45;
|
||||
border-bottom: 1px solid #53565B;
|
||||
|
@ -88,41 +120,6 @@ body {
|
|||
min-height: 42px;
|
||||
max-width: 1170px;
|
||||
}
|
||||
|
||||
.select-rcue {
|
||||
font-size: 0.76923076923077em;
|
||||
margin-left: 1em;
|
||||
margin-top: 0.7em;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
background-color: #555a5e;
|
||||
background-image: none;
|
||||
background-image: url(img/sprite-arrow-down.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right -26px;
|
||||
border: 1px solid #676c6e;
|
||||
border-radius: 2px;
|
||||
padding-left: 0;
|
||||
|
||||
&:hover {
|
||||
border-color: #7e8385;
|
||||
}
|
||||
|
||||
select {
|
||||
color: #fff;
|
||||
|
||||
&:-moz-focusring {
|
||||
color: transparent;
|
||||
text-shadow: 0 0 0 #fff;
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
padding: 0.36363636363636em 0.90909090909091em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav > li {
|
||||
|
||||
|
@ -165,7 +162,6 @@ body {
|
|||
option {
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
padding: 0.36363636363636em 0.90909090909091em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -567,6 +563,59 @@ td.token-cell button {
|
|||
}
|
||||
|
||||
|
||||
/* Modal boxes */
|
||||
|
||||
.modal {
|
||||
|
||||
.modal-dialog {
|
||||
padding-top: 10em;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: #f8f8f8;
|
||||
padding: 1.5em 2em;
|
||||
border-bottom: none;
|
||||
|
||||
h3 {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
font-family: @open-sans;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
|
||||
p {
|
||||
font-size: 1.1em;
|
||||
|
||||
&.primary {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.45454545454545em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-top: 0;
|
||||
|
||||
.primary,
|
||||
.destructive {
|
||||
float: right;
|
||||
margin-left: 0.90909090909091em;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Page: User Account */
|
||||
|
||||
.user {
|
||||
|
|
|
@ -16,12 +16,14 @@ input[type="email"],
|
|||
textarea {
|
||||
font-size: 1.1em;
|
||||
padding: 0 0.545454545454545em;
|
||||
min-width: 18.1818181818182em;
|
||||
height: 2.36363636363636em;
|
||||
/* 26px */
|
||||
|
||||
border: 1px #b6b6b6 solid;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
|
||||
color: #333;
|
||||
width: 18.1818em;
|
||||
}
|
||||
input[type="text"]:hover,
|
||||
input[type="password"]:hover,
|
||||
|
@ -51,6 +53,36 @@ input[type="email"].error:focus,
|
|||
textarea.error:focus {
|
||||
box-shadow: 0 0 5px #ba1212;
|
||||
}
|
||||
input[type="text"].tiny,
|
||||
input[type="password"].tiny,
|
||||
input[type="email"].tiny,
|
||||
textarea.tiny {
|
||||
width: 4.54545454545455em;
|
||||
}
|
||||
input[type="text"].small,
|
||||
input[type="password"].small,
|
||||
input[type="email"].small,
|
||||
textarea.small {
|
||||
width: 9.09090909090909em;
|
||||
}
|
||||
input[type="text"].medium,
|
||||
input[type="password"].medium,
|
||||
input[type="email"].medium,
|
||||
textarea.medium {
|
||||
width: 18.1818em;
|
||||
}
|
||||
input[type="text"].large,
|
||||
input[type="password"].large,
|
||||
input[type="email"].large,
|
||||
textarea.large {
|
||||
width: 27.2727272727273em;
|
||||
}
|
||||
input[type="text"].xlarge,
|
||||
input[type="password"].xlarge,
|
||||
input[type="email"].xlarge,
|
||||
textarea.xlarge {
|
||||
width: 36.3636363636364em;
|
||||
}
|
||||
textarea {
|
||||
padding: 0.45em 0.545454545454545em;
|
||||
height: auto;
|
||||
|
@ -252,7 +284,7 @@ button.primary:focus,
|
|||
.search-comp .icon-search {
|
||||
position: absolute;
|
||||
right: 0.2em;
|
||||
top: 0.4em;
|
||||
top: 0.6em;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
|
@ -457,6 +489,8 @@ fieldset.border-top {
|
|||
.form-group .required {
|
||||
font-size: 1.1em;
|
||||
color: #CB2915;
|
||||
display: inline-block;
|
||||
margin-top: -0.09090909090909em;
|
||||
}
|
||||
legend + .form-group {
|
||||
padding-top: 1em;
|
||||
|
@ -550,7 +584,7 @@ input[type="email"].tiny {
|
|||
}
|
||||
.select-rcue,
|
||||
.select2-container .select2-choice {
|
||||
height: 26px;
|
||||
height: 2.6em;
|
||||
border: 1px #b6b6b6 solid;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
|
||||
|
@ -593,7 +627,7 @@ input[type="email"].tiny {
|
|||
}
|
||||
.select-rcue option {
|
||||
line-height: 2em;
|
||||
padding-left: 0.90909090909091em;
|
||||
padding: 0.363636em 0.909091em;
|
||||
}
|
||||
.select-rcue option:hover {
|
||||
background-color: #d5ecf9;
|
||||
|
@ -788,7 +822,8 @@ input[type="email"].tiny {
|
|||
margin-top: 3em;
|
||||
margin-bottom: 5em;
|
||||
}
|
||||
.form-actions .primary {
|
||||
.form-actions .primary,
|
||||
.form-actions .destructive {
|
||||
float: right;
|
||||
margin-left: 0.90909090909091em;
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ input[type="email"],
|
|||
textarea {
|
||||
font-size: 1.1em;
|
||||
padding: 0 0.545454545454545em;
|
||||
min-width: 18.1818181818182em;
|
||||
height: 2.36363636363636em;
|
||||
height: 2.36363636363636em; /* 26px */
|
||||
border: 1px #b6b6b6 solid;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0,0,0,0.1);
|
||||
color: #333;
|
||||
width: 18.1818em;
|
||||
|
||||
&:hover {
|
||||
border-color: #62afdb;
|
||||
|
@ -49,6 +49,26 @@ textarea {
|
|||
box-shadow: 0 0 5px #ba1212;
|
||||
}
|
||||
}
|
||||
|
||||
&.tiny {
|
||||
width: 4.54545454545455em;
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: 9.09090909090909em;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
width: 18.1818em;
|
||||
}
|
||||
|
||||
&.large {
|
||||
width: 27.2727272727273em;
|
||||
}
|
||||
|
||||
&.xlarge {
|
||||
width: 36.3636363636364em
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
@ -280,7 +300,7 @@ button.primary,
|
|||
.icon-search {
|
||||
position: absolute;
|
||||
right: 0.2em;
|
||||
top: 0.4em;
|
||||
top: 0.6em;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
|
||||
|
@ -532,6 +552,8 @@ fieldset.border-top {
|
|||
.required {
|
||||
font-size: 1.1em;
|
||||
color: #CB2915;
|
||||
display: inline-block;
|
||||
margin-top: -0.09090909090909em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,7 +678,7 @@ input[type="email"] {
|
|||
|
||||
.select-rcue,
|
||||
.select2-container .select2-choice {
|
||||
height: 26px;
|
||||
height: 2.6em;
|
||||
border: 1px #b6b6b6 solid;
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0px 2px 2px rgba(0,0,0,0.1);
|
||||
|
@ -707,7 +729,7 @@ input[type="email"] {
|
|||
|
||||
option {
|
||||
line-height: 2em;
|
||||
padding-left: 0.90909090909091em;
|
||||
padding: 0.363636em 0.909091em;
|
||||
|
||||
&:hover {
|
||||
background-color: #d5ecf9;
|
||||
|
@ -940,7 +962,8 @@ input[type="email"] {
|
|||
margin-top: 3em;
|
||||
margin-bottom: 5em;
|
||||
|
||||
.primary {
|
||||
.primary,
|
||||
.destructive {
|
||||
float: right;
|
||||
margin-left: 0.90909090909091em;
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 338 B |
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="12px" height="400px" viewBox="0 0 12 400" enable-background="new 0 0 12 400" xml:space="preserve">
|
||||
<rect x="6.001" opacity="0.07" fill="#FFFFFF" enable-background="new " width="0.997" height="190"/>
|
||||
<rect x="6" y="209" opacity="0.07" fill="#FFFFFF" enable-background="new " width="1" height="191"/>
|
||||
<g opacity="0.15">
|
||||
<path fill="#FFFFFF" d="M6.501,200.066c0,1.047-0.264,1.864-0.791,2.452S4.454,203.4,3.524,203.4c-0.574,0-1.084-0.135-1.529-0.404
|
||||
c-0.445-0.27-0.789-0.656-1.031-1.16c-0.242-0.504-0.363-1.094-0.363-1.77c0-1.047,0.262-1.862,0.785-2.446
|
||||
c0.523-0.584,1.25-0.876,2.18-0.876c0.898,0,1.612,0.299,2.142,0.896C6.238,198.237,6.501,199.047,6.501,200.066z M1.608,200.066
|
||||
c0,0.821,0.164,1.446,0.492,1.875s0.811,0.645,1.447,0.645c0.636,0,1.12-0.214,1.45-0.643c0.33-0.428,0.495-1.053,0.495-1.877
|
||||
c0-0.816-0.165-1.437-0.495-1.86s-0.817-0.636-1.462-0.636c-0.637,0-1.117,0.209-1.441,0.627
|
||||
C1.77,198.615,1.608,199.238,1.608,200.066z"/>
|
||||
<path fill="#FFFFFF" d="M11.136,196.744c0.285,0,0.541,0.023,0.768,0.07l-0.135,0.902c-0.266-0.059-0.5-0.088-0.703-0.088
|
||||
c-0.52,0-0.964,0.211-1.333,0.633c-0.369,0.422-0.554,0.947-0.554,1.576v3.445H8.206v-6.422h0.803l0.111,1.189h0.047
|
||||
c0.238-0.418,0.525-0.74,0.861-0.967C10.364,196.855,10.733,196.744,11.136,196.744z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
|
@ -1,284 +0,0 @@
|
|||
body {
|
||||
font-size: 62.5%;
|
||||
min-height: 60em;
|
||||
min-width: 120em;
|
||||
}
|
||||
.rcue-login-register {
|
||||
background-color: #1D2226;
|
||||
background-image: url("img/login-screen-background.jpg");
|
||||
background-position: top left;
|
||||
background-size: auto;
|
||||
background-repeat: no-repeat;
|
||||
color: #fff;
|
||||
/*
|
||||
.form-area {
|
||||
background-image: url(img/login-register-separator.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 40.2em center;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Login area */
|
||||
|
||||
/* Social login area */
|
||||
|
||||
/* Info area */
|
||||
|
||||
}
|
||||
.rcue-login-register h1 a {
|
||||
position: absolute;
|
||||
top: 5em;
|
||||
right: 6.4em;
|
||||
}
|
||||
.rcue-login-register .content {
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
width: 100%;
|
||||
min-width: 76em;
|
||||
}
|
||||
.rcue-login-register h2 {
|
||||
padding-left: 4.34782608695652em;
|
||||
font-family: "Overpass", sans-serif;
|
||||
font-size: 2.3em;
|
||||
font-weight: 100;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.005em;
|
||||
}
|
||||
.rcue-login-register h2 strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
.rcue-login-register .background-area {
|
||||
border-top: 0.1em rgba(255, 255, 255, 0.05) solid;
|
||||
border-bottom: 0.1em rgba(255, 255, 255, 0.05) solid;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
padding: 3em 0 3em 10em;
|
||||
margin-top: 2.7em;
|
||||
width: 100%;
|
||||
min-width: 120em;
|
||||
}
|
||||
.rcue-login-register .background-area section {
|
||||
float: left;
|
||||
padding: 1.5em 4.5em 1.5em 4.6em;
|
||||
width: auto;
|
||||
position: relative;
|
||||
}
|
||||
.rcue-login-register .background-area section h3 {
|
||||
display: none;
|
||||
}
|
||||
.rcue-login-register .background-area section:first-child {
|
||||
padding-right: 4.5em;
|
||||
}
|
||||
.rcue-login-register .form-area.social {
|
||||
background-image: url(img/login-register-social-separators.svg);
|
||||
background-position: 39.6em center;
|
||||
}
|
||||
.rcue-login-register section.app-form {
|
||||
padding-left: 0;
|
||||
position: relative;
|
||||
}
|
||||
.rcue-login-register form > div {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.rcue-login-register label,
|
||||
.rcue-login-register .social-login > p {
|
||||
display: inline-block;
|
||||
font-size: 1.4em;
|
||||
font-weight: 400;
|
||||
}
|
||||
.rcue-login-register label {
|
||||
width: 6.07142857142857em;
|
||||
/* 85px */
|
||||
|
||||
}
|
||||
.rcue-login-register label.two-lines {
|
||||
float: left;
|
||||
margin-top: -0.28571428571429em;
|
||||
/* -4px */
|
||||
|
||||
line-height: 1.1em;
|
||||
}
|
||||
.rcue-login-register input[type="text"],
|
||||
.rcue-login-register input[type="password"] {
|
||||
width: 24.7272727272727em;
|
||||
/* 272px */
|
||||
|
||||
}
|
||||
.rcue-login-register form > div.aside-btn {
|
||||
float: left;
|
||||
font-size: 1.1em;
|
||||
margin-left: 7.72727272727273em;
|
||||
/* 85px */
|
||||
|
||||
margin-top: 0.90909090909091em;
|
||||
/* 10px */
|
||||
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.rcue-login-register form > div.aside-btn label {
|
||||
font-size: 1em;
|
||||
width: auto;
|
||||
}
|
||||
.rcue-login-register form > div.aside-btn input[type="checkbox"] {
|
||||
margin-bottom: 0.54545454545455em;
|
||||
/* 6px */
|
||||
|
||||
}
|
||||
.rcue-login-register form > input[type="button"] {
|
||||
float: right;
|
||||
margin-top: 0.76923076923077em;
|
||||
/* 10px */
|
||||
|
||||
}
|
||||
.rcue-login-register p.subtitle {
|
||||
font-size: 1.1em;
|
||||
color: #999;
|
||||
position: absolute;
|
||||
right: 4.09090909090909em;
|
||||
top: -0.636363636363636em;
|
||||
}
|
||||
.rcue-login-register .feedback {
|
||||
left: 32.7em;
|
||||
top: -9.2em;
|
||||
min-width: 35em;
|
||||
}
|
||||
.rcue-login-register.reset .feedback {
|
||||
left: 35.7em;
|
||||
}
|
||||
.rcue-login-register section.social-login > span {
|
||||
display: none;
|
||||
}
|
||||
.rcue-login-register section.social-login > p {
|
||||
float: left;
|
||||
margin-top: 0.28571428571429em;
|
||||
/* 14px */
|
||||
|
||||
width: 6.78571428571429em;
|
||||
/* 95px */
|
||||
|
||||
}
|
||||
.rcue-login-register section.social-login > ul {
|
||||
float: left;
|
||||
}
|
||||
.rcue-login-register section.social-login li {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.rcue-login-register section.social-login li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.rcue-login-register section.info-area {
|
||||
padding-right: 0;
|
||||
}
|
||||
.rcue-login-register section.info-area p,
|
||||
.rcue-login-register section.info-area li {
|
||||
font-size: 1.4em;
|
||||
margin-bottom: 1.64285714285714em;
|
||||
/* 23px */
|
||||
|
||||
}
|
||||
.rcue-login-register section.info-area li {
|
||||
color: #999;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.rcue-login-register section.info-area li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media screen and (min-width: 1280px) {
|
||||
.rcue-login-register {
|
||||
background-size: 100% auto;
|
||||
}
|
||||
}
|
||||
/* Social buttons */
|
||||
.zocial,
|
||||
a.zocial {
|
||||
padding: 0;
|
||||
line-height: 2.3em;
|
||||
height: 2.3em;
|
||||
width: 131px;
|
||||
border-radius: 2px;
|
||||
box-shadow: none;
|
||||
background-image: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
.zocial .text,
|
||||
a.zocial .text {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.25em;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: normal;
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.15);
|
||||
margin-left: 3em;
|
||||
/* 36 px */
|
||||
|
||||
margin-top: 0.25em;
|
||||
/* 3px */
|
||||
|
||||
}
|
||||
.zocial:hover,
|
||||
a.zocial:hover,
|
||||
.zocial:active,
|
||||
a.zocial:active,
|
||||
.zocial:focus,
|
||||
a.zocial:focus {
|
||||
text-decoration: none;
|
||||
background-image: none;
|
||||
}
|
||||
.zocial:hover,
|
||||
a.zocial:hover {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);
|
||||
}
|
||||
.zocial:before,
|
||||
a.zocial:before {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
width: 3em;
|
||||
/* 36px */
|
||||
|
||||
}
|
||||
.zocial.facebook:before {
|
||||
width: 2.66666666666667em;
|
||||
/* 32px */
|
||||
}
|
||||
/* Register page */
|
||||
.rcue-login-register.register label {
|
||||
width: 7.5em;
|
||||
/* 105px */
|
||||
|
||||
}
|
||||
.rcue-login-register.register input[type="text"],
|
||||
.rcue-login-register.register input[type="email"],
|
||||
.rcue-login-register.register input[type="password"] {
|
||||
width: 22.9090909090909em;
|
||||
/* 252px */
|
||||
|
||||
}
|
||||
.rcue-login-register.register form > div.aside-btn {
|
||||
margin-left: 9.54545454545454em;
|
||||
/* 105px */
|
||||
|
||||
width: 12.5454545454546em;
|
||||
/* 138px */
|
||||
|
||||
}
|
||||
.rcue-login-register.register form > div.aside-btn p {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
/* Customer login */
|
||||
.rcue-login-register.customer {
|
||||
background-image: url("img/customer-login-screen-bg2.jpg");
|
||||
}
|
||||
.rcue-login-register.customer p.powered {
|
||||
font-size: 1.1em;
|
||||
margin-top: 1.27272727272727em;
|
||||
text-align: right;
|
||||
margin-right: 5.81818181818182em;
|
||||
}
|
||||
.rcue-login-register.customer p.powered a {
|
||||
color: #666;
|
||||
}
|
||||
.rcue-login-register.customer p.powered a:hover {
|
||||
color: #0099D3;
|
||||
}
|
|
@ -1,322 +0,0 @@
|
|||
body {
|
||||
font-size: 62.5%;
|
||||
min-height: 60em;
|
||||
min-width: 120em;
|
||||
}
|
||||
|
||||
.rcue-login-register {
|
||||
background-color: #1D2226;
|
||||
background-image: url("img/login-screen-background.jpg");
|
||||
background-position: top left;
|
||||
background-size: auto;
|
||||
background-repeat: no-repeat;
|
||||
color: #fff;
|
||||
|
||||
h1 a {
|
||||
position: absolute;
|
||||
top: 5em;
|
||||
right: 6.4em;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: absolute;
|
||||
bottom: 10%;
|
||||
width: 100%;
|
||||
min-width: 76em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-left: 4.34782608695652em;
|
||||
font-family: "Overpass", sans-serif;
|
||||
font-size: 2.3em;
|
||||
font-weight: 100;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.005em;
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.background-area {
|
||||
border-top: 0.1em rgba(255, 255, 255, 0.05) solid;
|
||||
border-bottom: 0.1em rgba(255, 255, 255, 0.05) solid;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
padding: 3em 0 3em 10em;
|
||||
margin-top: 2.7em;
|
||||
width: 100%;
|
||||
min-width: 120em;
|
||||
|
||||
section {
|
||||
float: left;
|
||||
padding: 1.5em 4.5em 1.5em 4.6em;
|
||||
width: auto;
|
||||
position: relative;
|
||||
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
padding-right: 4.5em;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
.form-area {
|
||||
background-image: url(img/login-register-separator.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 40.2em center;
|
||||
}
|
||||
*/
|
||||
|
||||
.form-area.social {
|
||||
background-image: url(img/login-register-social-separators.svg);
|
||||
background-position: 39.6em center;
|
||||
}
|
||||
|
||||
|
||||
/* Login area */
|
||||
|
||||
section.app-form {
|
||||
padding-left: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
form > div {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
label,
|
||||
.social-login > p {
|
||||
display: inline-block;
|
||||
font-size: 1.4em;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
label {
|
||||
width: 6.07142857142857em; /* 85px */
|
||||
}
|
||||
|
||||
label.two-lines {
|
||||
float: left;
|
||||
margin-top: -0.28571428571429em; /* -4px */
|
||||
line-height: 1.1em;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 24.7272727272727em; /* 272px */
|
||||
}
|
||||
|
||||
form > div.aside-btn {
|
||||
float: left;
|
||||
font-size: 1.1em;
|
||||
margin-left: 7.72727272727273em; /* 85px */
|
||||
margin-top: 0.90909090909091em; /* 10px */
|
||||
margin-bottom: 0;
|
||||
|
||||
label {
|
||||
font-size: 1em;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin-bottom: 0.54545454545455em; /* 6px */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
form > input[type="button"] {
|
||||
float: right;
|
||||
margin-top: 0.76923076923077em; /* 10px */
|
||||
}
|
||||
|
||||
p.subtitle {
|
||||
font-size: 1.1em;
|
||||
color: #999;
|
||||
position: absolute;
|
||||
right: 4.09090909090909em;
|
||||
top: -0.636363636363636em;
|
||||
}
|
||||
|
||||
.feedback {
|
||||
left: 32.7em;
|
||||
top: -9.2em;
|
||||
min-width: 35em;
|
||||
}
|
||||
|
||||
&.reset .feedback {
|
||||
left: 35.7em;
|
||||
}
|
||||
|
||||
|
||||
/* Social login area */
|
||||
|
||||
section.social-login {
|
||||
|
||||
> span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> p {
|
||||
float: left;
|
||||
margin-top: 0.28571428571429em; /* 14px */
|
||||
width: 6.78571428571429em; /* 95px */
|
||||
}
|
||||
|
||||
> ul {
|
||||
float: left;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 2em;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Info area */
|
||||
|
||||
section.info-area {
|
||||
|
||||
padding-right: 0;
|
||||
|
||||
p,
|
||||
li {
|
||||
font-size: 1.4em;
|
||||
margin-bottom: 1.64285714285714em; /* 23px */
|
||||
}
|
||||
|
||||
li {
|
||||
color: #999;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1280px) {
|
||||
.rcue-login-register {
|
||||
background-size: 100% auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Social buttons */
|
||||
|
||||
.zocial,
|
||||
a.zocial {
|
||||
padding: 0;
|
||||
line-height: 2.3em;
|
||||
height: 2.3em;
|
||||
width: 131px;
|
||||
border-radius: 2px;
|
||||
box-shadow: none;
|
||||
background-image: none;
|
||||
text-shadow: none;
|
||||
|
||||
.text {
|
||||
font-size: 1.2em;
|
||||
line-height: 1.25em;
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: normal;
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.15);
|
||||
margin-left: 3em; /* 36 px */
|
||||
margin-top: 0.25em; /* 3px */
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
text-decoration: none;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);
|
||||
}
|
||||
|
||||
&:before {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
width: 3em; /* 36px */
|
||||
}
|
||||
}
|
||||
|
||||
.zocial.facebook:before {
|
||||
width: 2.66666666666667em; /* 32px */
|
||||
}
|
||||
|
||||
|
||||
/* Register page */
|
||||
|
||||
.rcue-login-register.register {
|
||||
|
||||
label {
|
||||
width: 7.5em; /* 105px */
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"] {
|
||||
width: 22.9090909090909em; /* 252px */
|
||||
}
|
||||
|
||||
form > div.aside-btn {
|
||||
margin-left: 9.54545454545454em; /* 105px */
|
||||
width: 12.5454545454546em; /* 138px */
|
||||
|
||||
p {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Customer login */
|
||||
|
||||
.rcue-login-register.customer {
|
||||
background-image: url("img/customer-login-screen-bg2.jpg");
|
||||
|
||||
p.powered {
|
||||
font-size: 1.1em;
|
||||
margin-top: 1.27272727272727em;
|
||||
text-align: right;
|
||||
margin-right: 5.81818181818182em;
|
||||
|
||||
a {
|
||||
color: #666;
|
||||
|
||||
&:hover {
|
||||
color: #0099D3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -5,12 +5,6 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Keycloak</title>
|
||||
|
||||
<style type="text/css">
|
||||
#idletimeout { background:#CC5100; border:3px solid #FF6500; color:#fff; font-family:arial, sans-serif; text-align:center; font-size:12px; padding:10px; position:relative; top:0px; left:0; right:0; z-index:100000; display:none; }
|
||||
#idletimeout a { color:#fff; font-weight:bold }
|
||||
#idletimeout span { font-weight:bold }
|
||||
</style>
|
||||
|
||||
<link rel="icon" href="/auth-server/admin-ui/img/favicon.ico">
|
||||
|
||||
<!-- Frameworks -->
|
||||
|
@ -59,7 +53,7 @@
|
|||
|
||||
<body class="admin-console" data-ng-controller="GlobalCtrl">
|
||||
<div id="idletimeout">
|
||||
You will be logged off in <span></span> seconds due to inactivity.
|
||||
You will be logged off in <strong><span></span> seconds</strong> due to inactivity.
|
||||
<a id="idletimeout-resume" href="#">Click here to continue using this web page</a>.
|
||||
</div>
|
||||
|
||||
|
|
|
@ -4,29 +4,31 @@ var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders
|
|||
var resourceRequests = 0;
|
||||
|
||||
module.config([ '$routeProvider', function($routeProvider) {
|
||||
|
||||
$routeProvider
|
||||
|
||||
.when('/create/realm', {
|
||||
templateUrl : 'partials/realm-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
controller : 'RealmDetailCtrl'
|
||||
}).when('/realms/:realm', {
|
||||
templateUrl : 'partials/realm-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmDetailCtrl'
|
||||
}).when('/realms', {
|
||||
templateUrl : 'partials/realm-list.html',
|
||||
controller : 'RealmListCtrl'
|
||||
}).when('/realms/:realm/token-settings', {
|
||||
$routeProvider
|
||||
.when('/create/realm', {
|
||||
templateUrl : 'partials/realm-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
controller : 'RealmDetailCtrl'
|
||||
})
|
||||
.when('/realms/:realm', {
|
||||
templateUrl : 'partials/realm-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmDetailCtrl'
|
||||
})
|
||||
.when('/realms', {
|
||||
templateUrl : 'partials/realm-list.html',
|
||||
controller : 'RealmListCtrl'
|
||||
})
|
||||
.when('/realms/:realm/token-settings', {
|
||||
templateUrl : 'partials/realm-tokens.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -34,7 +36,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'RealmTokenDetailCtrl'
|
||||
}).when('/realms/:realm/social-settings', {
|
||||
})
|
||||
.when('/realms/:realm/social-settings', {
|
||||
templateUrl : 'partials/realm-social.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -52,18 +55,28 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'RealmRequiredCredentialsCtrl'
|
||||
})
|
||||
.when('/create/user/:realm', {
|
||||
templateUrl : 'partials/user-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
user : function() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
controller : 'UserDetailCtrl'
|
||||
}).when('/realms/:realm/users/:user', {
|
||||
.when('/realms/:realm/smtp-settings', {
|
||||
templateUrl : 'partials/realm-smtp.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmSMTPSettingsCtrl'
|
||||
})
|
||||
.when('/create/user/:realm', {
|
||||
templateUrl : 'partials/user-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
user : function() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
controller : 'UserDetailCtrl'
|
||||
})
|
||||
.when('/realms/:realm/users/:user', {
|
||||
templateUrl : 'partials/user-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -74,7 +87,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'UserDetailCtrl'
|
||||
}).when('/realms/:realm/users/:user/role-mappings', {
|
||||
})
|
||||
.when('/realms/:realm/users/:user/role-mappings', {
|
||||
templateUrl : 'partials/role-mappings.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -91,15 +105,16 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'UserRoleMappingCtrl'
|
||||
}).when('/realms/:realm/users', {
|
||||
templateUrl : 'partials/user-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'UserListCtrl'
|
||||
})
|
||||
})
|
||||
.when('/realms/:realm/users', {
|
||||
templateUrl : 'partials/user-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
}
|
||||
},
|
||||
controller : 'UserListCtrl'
|
||||
})
|
||||
|
||||
.when('/create/role/:realm', {
|
||||
templateUrl : 'partials/role-detail.html',
|
||||
|
@ -112,7 +127,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'RoleDetailCtrl'
|
||||
}).when('/realms/:realm/roles/:role', {
|
||||
})
|
||||
.when('/realms/:realm/roles/:role', {
|
||||
templateUrl : 'partials/role-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -123,7 +139,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'RoleDetailCtrl'
|
||||
}).when('/realms/:realm/roles', {
|
||||
})
|
||||
.when('/realms/:realm/roles', {
|
||||
templateUrl : 'partials/role-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -150,7 +167,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationRoleDetailCtrl'
|
||||
}).when('/realms/:realm/applications/:application/roles/:role', {
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/roles/:role', {
|
||||
templateUrl : 'partials/application-role-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -164,7 +182,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationRoleDetailCtrl'
|
||||
}).when('/realms/:realm/applications/:application/credentials', {
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/credentials', {
|
||||
templateUrl : 'partials/application-credentials.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -175,7 +194,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationCredentialsCtrl'
|
||||
}).when('/realms/:realm/applications/:application/roles', {
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/roles', {
|
||||
templateUrl : 'partials/application-role-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -189,7 +209,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationRoleListCtrl'
|
||||
}).when('/realms/:realm/applications/:application/scope-mappings', {
|
||||
})
|
||||
.when('/realms/:realm/applications/:application/scope-mappings', {
|
||||
templateUrl : 'partials/application-scope-mappings.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -208,8 +229,6 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
controller : 'ApplicationScopeMappingCtrl'
|
||||
})
|
||||
|
||||
|
||||
|
||||
.when('/create/application/:realm', {
|
||||
templateUrl : 'partials/application-detail.html',
|
||||
resolve : {
|
||||
|
@ -224,7 +243,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationDetailCtrl'
|
||||
}).when('/realms/:realm/applications/:application', {
|
||||
})
|
||||
.when('/realms/:realm/applications/:application', {
|
||||
templateUrl : 'partials/application-detail.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -238,7 +258,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
}
|
||||
},
|
||||
controller : 'ApplicationDetailCtrl'
|
||||
}).when('/realms/:realm/applications', {
|
||||
})
|
||||
.when('/realms/:realm/applications', {
|
||||
templateUrl : 'partials/application-list.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
|
@ -250,33 +271,33 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'ApplicationListCtrl'
|
||||
})
|
||||
.otherwise({
|
||||
templateUrl : 'partials/home.html'
|
||||
});
|
||||
.otherwise({
|
||||
templateUrl : 'partials/home.html'
|
||||
});
|
||||
} ]);
|
||||
|
||||
module.config(function($httpProvider) {
|
||||
$httpProvider.responseInterceptors.push('errorInterceptor');
|
||||
$httpProvider.responseInterceptors.push('errorInterceptor');
|
||||
|
||||
var spinnerFunction = function(data, headersGetter) {
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').show();
|
||||
}
|
||||
resourceRequests++;
|
||||
return data;
|
||||
};
|
||||
$httpProvider.defaults.transformRequest.push(spinnerFunction);
|
||||
var spinnerFunction = function(data, headersGetter) {
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').show();
|
||||
}
|
||||
resourceRequests++;
|
||||
return data;
|
||||
};
|
||||
$httpProvider.defaults.transformRequest.push(spinnerFunction);
|
||||
|
||||
$httpProvider.responseInterceptors.push('spinnerInterceptor');
|
||||
$httpProvider.responseInterceptors.push('spinnerInterceptor');
|
||||
|
||||
});
|
||||
|
||||
module.factory('errorInterceptor', function($q, $window, $rootScope, $location, Auth) {
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
$rootScope.httpProviderError = null;
|
||||
return response;
|
||||
}, function(response) {
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
$rootScope.httpProviderError = null;
|
||||
return response;
|
||||
}, function(response) {
|
||||
if (response.status == 401) {
|
||||
console.log('session timeout?');
|
||||
Auth.loggedIn = false;
|
||||
|
@ -284,28 +305,28 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location,
|
|||
} else {
|
||||
$rootScope.httpProviderError = response.status;
|
||||
}
|
||||
return $q.reject(response);
|
||||
});
|
||||
};
|
||||
return $q.reject(response);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location) {
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
resourceRequests--;
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').hide();
|
||||
}
|
||||
return response;
|
||||
}, function(response) {
|
||||
resourceRequests--;
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').hide();
|
||||
}
|
||||
return function(promise) {
|
||||
return promise.then(function(response) {
|
||||
resourceRequests--;
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').hide();
|
||||
}
|
||||
return response;
|
||||
}, function(response) {
|
||||
resourceRequests--;
|
||||
if (resourceRequests == 0) {
|
||||
$('#loading').hide();
|
||||
}
|
||||
|
||||
return $q.reject(response);
|
||||
});
|
||||
};
|
||||
return $q.reject(response);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
// collapsable form fieldsets
|
||||
|
@ -354,80 +375,80 @@ module.directive('collapsed', function() {
|
|||
|
||||
|
||||
module.directive('kcInput', function() {
|
||||
var d = {
|
||||
scope : true,
|
||||
replace : false,
|
||||
link : function(scope, element, attrs) {
|
||||
var form = element.children('form');
|
||||
var label = element.children('label');
|
||||
var input = element.children('input');
|
||||
var d = {
|
||||
scope : true,
|
||||
replace : false,
|
||||
link : function(scope, element, attrs) {
|
||||
var form = element.children('form');
|
||||
var label = element.children('label');
|
||||
var input = element.children('input');
|
||||
|
||||
var id = form.attr('name') + '.' + input.attr('name');
|
||||
var id = form.attr('name') + '.' + input.attr('name');
|
||||
|
||||
element.attr('class', 'control-group');
|
||||
element.attr('class', 'control-group');
|
||||
|
||||
label.attr('class', 'control-label');
|
||||
label.attr('for', id);
|
||||
label.attr('class', 'control-label');
|
||||
label.attr('for', id);
|
||||
|
||||
input.wrap('<div class="controls"/>');
|
||||
input.attr('id', id);
|
||||
input.wrap('<div class="controls"/>');
|
||||
input.attr('id', id);
|
||||
|
||||
if (!input.attr('placeHolder')) {
|
||||
input.attr('placeHolder', label.text());
|
||||
}
|
||||
if (!input.attr('placeHolder')) {
|
||||
input.attr('placeHolder', label.text());
|
||||
}
|
||||
|
||||
if (input.attr('required')) {
|
||||
label.append(' <span class="required">*</span>');
|
||||
}
|
||||
}
|
||||
};
|
||||
return d;
|
||||
if (input.attr('required')) {
|
||||
label.append(' <span class="required">*</span>');
|
||||
}
|
||||
}
|
||||
};
|
||||
return d;
|
||||
});
|
||||
|
||||
module.directive('kcEnter', function() {
|
||||
return function(scope, element, attrs) {
|
||||
element.bind("keydown keypress", function(event) {
|
||||
if (event.which === 13) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.kcEnter);
|
||||
});
|
||||
return function(scope, element, attrs) {
|
||||
element.bind("keydown keypress", function(event) {
|
||||
if (event.which === 13) {
|
||||
scope.$apply(function() {
|
||||
scope.$eval(attrs.kcEnter);
|
||||
});
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
module.filter('remove', function() {
|
||||
return function(input, remove, attribute) {
|
||||
if (!input || !remove) {
|
||||
return input;
|
||||
}
|
||||
return function(input, remove, attribute) {
|
||||
if (!input || !remove) {
|
||||
return input;
|
||||
}
|
||||
|
||||
var out = [];
|
||||
for ( var i = 0; i < input.length; i++) {
|
||||
var e = input[i];
|
||||
var out = [];
|
||||
for ( var i = 0; i < input.length; i++) {
|
||||
var e = input[i];
|
||||
|
||||
for (var j = 0; j < remove.length; j++) {
|
||||
if (attribute) {
|
||||
if (remove[j][attribute] == e[attribute]) {
|
||||
e = null;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (remove[j] == e) {
|
||||
e = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < remove.length; j++) {
|
||||
if (attribute) {
|
||||
if (remove[j][attribute] == e[attribute]) {
|
||||
e = null;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (remove[j] == e) {
|
||||
e = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e != null) {
|
||||
out.push(e);
|
||||
}
|
||||
}
|
||||
if (e != null) {
|
||||
out.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
return out;
|
||||
};
|
||||
});
|
|
@ -453,3 +453,38 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
|
|||
});
|
||||
};
|
||||
});
|
||||
|
||||
module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
|
||||
$scope.realm = {
|
||||
id : realm.id, realm : realm.realm, social : realm.social,
|
||||
smtpServer: realm.smtpServer
|
||||
};
|
||||
|
||||
var oldCopy = angular.copy($scope.realm);
|
||||
$scope.changed = false;
|
||||
|
||||
$scope.$watch('realm', function() {
|
||||
if (!angular.equals($scope.realm, oldCopy)) {
|
||||
$scope.changed = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
$scope.save = function() {
|
||||
if ($scope.realmForm.$valid) {
|
||||
var realmCopy = angular.copy($scope.realm);
|
||||
$scope.changed = false;
|
||||
Realm.update(realmCopy, function () {
|
||||
$location.url("/realms/" + realm.id + "/smtp-settings");
|
||||
Notifications.success("Your changes have been saved to the realm.");
|
||||
});
|
||||
} else {
|
||||
$scope.realmForm.showErrors = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
$scope.realm = angular.copy(oldCopy);
|
||||
$scope.changed = false;
|
||||
$scope.realmForm.showErrors = false;
|
||||
};
|
||||
});
|
|
@ -16,15 +16,16 @@ module.service('Auth', function() {
|
|||
module.service('Dialog', function($dialog) {
|
||||
var dialog = {};
|
||||
dialog.confirmDelete = function(name, type, success) {
|
||||
var title = 'Delete ' + name;
|
||||
var msg = 'Are you sure you want to permanently delete this ' + type + '?';
|
||||
var title = 'Delete ' + type.charAt(0).toUpperCase() + type.slice(1);
|
||||
var msg = '<p class="primary">Are you sure you want to permanently delete the ' + type + ' "' + name + '"?</p>' +
|
||||
'<p>This action can\'t be undone.</p>';
|
||||
var btns = [ {
|
||||
result : 'cancel',
|
||||
label : 'Cancel'
|
||||
}, {
|
||||
result : 'ok',
|
||||
label : 'Delete this ' + type,
|
||||
cssClass : 'btn-primary'
|
||||
label : 'Delete',
|
||||
cssClass : 'destructive'
|
||||
} ];
|
||||
|
||||
$dialog.messageBox(title, msg, btns).open().then(function(result) {
|
||||
|
|
|
@ -3004,10 +3004,10 @@ angular.module("template/dialog/message.html", []).run(["$templateCache", functi
|
|||
" <h3>{{ title }}</h3>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"modal-body\">\n" +
|
||||
" <p>{{ message }}</p>\n" +
|
||||
" <p ng-bind-html-unsafe=\"message\"></p>\n" +
|
||||
"</div>\n" +
|
||||
"<div class=\"modal-footer\">\n" +
|
||||
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"btn\" ng-class=\"btn.cssClass\">{{ btn.label }}</button>\n" +
|
||||
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"\" ng-class=\"btn.cssClass\">{{ btn.label }}</button> \n" +
|
||||
"</div>\n" +
|
||||
"</div>\n" +
|
||||
"</div>\n" +
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="header rcue">
|
||||
<div class="navbar utility">
|
||||
<div class="navbar-inner clearfix container">
|
||||
<h1><a href="#"><strong>Keycloak</strong> Central Login</a></h1>
|
||||
<h1><a href="#/realms/{{realm.id}}"><strong>Keycloak</strong> Central Login</a></h1>
|
||||
<ul class="nav pull-right" data-ng-hide="auth.loggedIn">
|
||||
<li><a href="/auth-server/rest/saas/login">Login</a></li>
|
||||
<li><a href="/auth-server/rest/saas/registrations">Register</a></li>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
@ -75,6 +76,32 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label for="resetPasswordAllowed" class="control-label">Reset password</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.resetPasswordAllowed" class="onoffswitch-checkbox" name="resetPasswordAllowed" id="resetPasswordAllowed">
|
||||
<label for="resetPasswordAllowed" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label for="verifyEmail" class="control-label">Verify email</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.verifyEmail" class="onoffswitch-checkbox" name="verifyEmail" id="verifyEmail">
|
||||
<label for="verifyEmail" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label for="accountManagement" class="control-label two-lines">User account management</label>
|
||||
<div class="onoffswitch">
|
||||
|
|
134
admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
Executable file
|
@ -0,0 +1,134 @@
|
|||
<div id="wrapper" class="container">
|
||||
<div class="row">
|
||||
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
<div class="top-nav" data-ng-hide="createRealm">
|
||||
<ul class="rcue-tabs">
|
||||
<li><a href="#/realms/{{realm.id}}">General</a></li>
|
||||
<li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}">Settings</a></li>
|
||||
<li class="active">SMTP Configuration</li>
|
||||
</ol>
|
||||
<h2><span>{{realm.realm}}</span> SMTP Settings</h2>
|
||||
<form name="realmForm" novalidate>
|
||||
<fieldset>
|
||||
<legend uncollapsed><span class="text">Required Settings</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpHost" class="control-label">Host <span class="required">*</span></label>
|
||||
<div class="controls">
|
||||
<input id="smtpHost" type="text" ng-model="realm.smtpServer.host" placeholder="SMTP Host" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpPort" class="control-label">Port <span class="required">*</span></label>
|
||||
<div class="controls">
|
||||
<input id="smtpPort" type="text" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpFrom" class="control-label">From <span class="required">*</span></label>
|
||||
<div class="controls">
|
||||
<input id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="SMTP From" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpSSL" class="control-label">Enable SSL</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.smtpServer.ssl" class="onoffswitch-checkbox" name="smtpSSL" id="smtpSSL">
|
||||
<label for="smtpSSL" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpStartTLS" class="control-label">Enable StartTLS</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.smtpServer.starttls" class="onoffswitch-checkbox" name="smtpStartTLS" id="smtpStartTLS">
|
||||
<label for="smtpStartTLS" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend collapsed><span class="text">Authentication</span></legend>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpAuth" class="control-label">Enabled</label>
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.smtpServer.auth" class="onoffswitch-checkbox" name="smtpAuth" id="smtpAuth">
|
||||
<label for="smtpAuth" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpUsername" class="control-label">Username <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
|
||||
<div class="controls">
|
||||
<input id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="Login Username" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label for="smtpPassword" class="control-label">Password <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
|
||||
<div class="controls">
|
||||
<input id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="Login Password" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<!--
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group clearfix" ng-repeat="(name, setting) in smtpSettings | orderBy: setting.required">
|
||||
<label for="{{name}}" class="control-label">{{name.replace('mail.smtp.','')}} <span class="required" data-ng-show="setting.required">*</span></label>
|
||||
|
||||
<div ng-show="setting.type == 'boolean'" class="onoffswitch">
|
||||
<input type="checkbox" data-ng-model="realm.smtp[name]" class="onoffswitch-checkbox" name="{{name}}" id="{{name}}">
|
||||
<label for="{{name}}" class="onoffswitch-label">
|
||||
<span class="onoffswitch-inner">
|
||||
<span class="onoffswitch-active">ON</span>
|
||||
<span class="onoffswitch-inactive">OFF</span>
|
||||
</span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div ng-show="setting.type == 'String'" class="controls">
|
||||
<input id="{{name}}" type="text" ng-model="realm.smtp[name]" placeholder="SMTP {{name}} / {{ setting.required }}">
|
||||
</div>
|
||||
<div ng-show="setting.type == 'int'" class="controls">
|
||||
<input id="{{name}}" type="number" ng-model="realm.smtp[name]" placeholder="SMTP {{name}} / {{ setting.required }}">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
-->
|
||||
<div class="form-actions">
|
||||
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
||||
</button>
|
||||
<button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-right-bg"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -9,6 +9,7 @@
|
|||
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
@ -92,7 +93,7 @@
|
|||
<div ng-include src="'partials/provider/'+ helpPId +'-help.html'"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" ng-click="closeHelp()">Close</button>
|
||||
<button ng-click="closeHelp()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
@ -49,7 +50,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group input-select">
|
||||
<label for="accessCodeLifespanUserAction">Access code user action lifespan</label>
|
||||
<label for="accessCodeLifespanUserAction" class="two-lines">Access code user action lifespan</label>
|
||||
<div class="input-group">
|
||||
<input type="text" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction" class="tiny">
|
||||
<div class="select-rcue">
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
|
||||
<li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
|
|
@ -18,6 +18,7 @@ public class ApplicationRepresentation {
|
|||
protected boolean enabled;
|
||||
protected List<CredentialRepresentation> credentials;
|
||||
protected List<RoleRepresentation> roles;
|
||||
protected String[] defaultRoles;
|
||||
protected List<UserRoleMappingRepresentation> roleMappings;
|
||||
protected List<ScopeMappingRepresentation> scopeMappings;
|
||||
protected List<String> redirectUris;
|
||||
|
@ -164,4 +165,12 @@ public class ApplicationRepresentation {
|
|||
public void setWebOrigins(List<String> webOrigins) {
|
||||
this.webOrigins = webOrigins;
|
||||
}
|
||||
|
||||
public String[] getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class RealmRepresentation {
|
|||
protected String privateKey;
|
||||
protected String publicKey;
|
||||
protected List<RoleRepresentation> roles;
|
||||
protected String[] defaultRoles;
|
||||
protected List<String> defaultRoles;
|
||||
protected Set<String> requiredCredentials;
|
||||
protected Set<String> requiredApplicationCredentials;
|
||||
protected Set<String> requiredOAuthClientCredentials;
|
||||
|
@ -220,11 +220,11 @@ public class RealmRepresentation {
|
|||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String[] getDefaultRoles() {
|
||||
public List<String> getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
public void setDefaultRoles(List<String> defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
|
||||
|
|
50
dist/assembly.xml
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly xmlns="urn:maven:assembly:1.1.0-SNAPSHOT">
|
||||
<id>distro</id>
|
||||
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${build.target.dir}</directory>
|
||||
<outputDirectory>keycloak-${project.version}</outputDirectory>
|
||||
<excludes>
|
||||
<exclude>**/*.sh</exclude>
|
||||
<exclude>domain/tmp/auth</exclude>
|
||||
<exclude>domain/tmp/auth</exclude>
|
||||
<exclude>**/*-users.properties</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${build.target.dir}</directory>
|
||||
<outputDirectory>keycloak-${project.version}</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${build.target.dir}</directory>
|
||||
<outputDirectory>keycloak-${project.version}</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*-users.properties</include>
|
||||
</includes>
|
||||
<fileMode>0600</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${build.target.dir}</directory>
|
||||
<outputDirectory>keycloak-${project.version}</outputDirectory>
|
||||
<includes>
|
||||
<include>domain/tmp/auth</include>
|
||||
<include>standalone/tmp/auth</include>
|
||||
</includes>
|
||||
<directoryMode>0700</directoryMode>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
</assembly>
|
37
dist/build.xml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<project name="keycloak-dist" basedir=".">
|
||||
<target name="jboss">
|
||||
<unzip src="${org.jboss.as:jboss-as-dist:zip}" dest="${project.build.directory}"/>
|
||||
<chmod perm="755">
|
||||
<fileset dir="${project.build.directory}/jboss-as-${jboss.version}/bin">
|
||||
<include name="**/*.sh"/>
|
||||
</fileset>
|
||||
</chmod>
|
||||
<move todir="${build.target.dir}" overwrite="true">
|
||||
<fileset dir="${project.build.directory}/jboss-as-${jboss.version}">
|
||||
<include name="**/*"/>
|
||||
</fileset>
|
||||
</move>
|
||||
<delete dir="${project.build.directory}/jboss-as-${jboss.version}"/>
|
||||
</target>
|
||||
|
||||
<target name="resteasy-modules">
|
||||
<get src="http://sourceforge.net/projects/resteasy/files/Resteasy%20JAX-RS/${resteasy.version}/resteasy-jaxrs-${resteasy.version}-all.zip"
|
||||
dest="${project.build.directory}" skipexisting="true"/>
|
||||
<unzip src="${project.build.directory}/resteasy-jaxrs-${resteasy.version}-all.zip"
|
||||
dest="${project.build.directory}">
|
||||
<patternset>
|
||||
<include name="resteasy-jaxrs-${resteasy.version}/resteasy-jboss-modules-${resteasy.version}.zip"/>
|
||||
</patternset>
|
||||
<mapper type="flatten"/>
|
||||
</unzip>
|
||||
<unzip src="${project.build.directory}/resteasy-jboss-modules-${resteasy.version}.zip"
|
||||
dest="${build.target.dir}/modules"/>
|
||||
</target>
|
||||
|
||||
<target name="keycloak-server">
|
||||
<copy file="${org.keycloak:keycloak-server:war}"
|
||||
tofile="${build.target.dir}/standalone/deployments/auth-server.war" overwrite="true"/>
|
||||
</target>
|
||||
|
||||
<target name="all" depends="jboss, resteasy-modules, keycloak-server"/>
|
||||
</project>
|
96
dist/pom.xml
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>1.0-alpha-1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>keycloak-dist</artifactId>
|
||||
<name>Keycloak Dist</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<build.target.dir>${project.build.directory}/keycloak-${project.version}</build.target.dir>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>release</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server</artifactId>
|
||||
<version>1.0-alpha-1</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.as</groupId>
|
||||
<artifactId>jboss-as-dist</artifactId>
|
||||
<version>${jboss.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build</id>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<ant antfile="build.xml" inheritRefs="false">
|
||||
<target name="all"/>
|
||||
</ant>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>keycloak-${project.version}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<outputDirectory>target/</outputDirectory>
|
||||
<workDirectory>target/assembly/work</workDirectory>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="keycloak.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
keycloak.init({
|
||||
clientId : '57572475438.apps.googleusercontent.com',
|
||||
clientSecret : 'xyfsPS9maRTz5fj0pOxf0zjD'
|
||||
});
|
||||
|
||||
if (keycloak.authenticated) {
|
||||
document.write('<h2>Token</h2><pre>' + keycloak.token + '</pre>');
|
||||
document.write('<h2>Token info</h2><pre>' + JSON.stringify(keycloak.tokenInfo, undefined, 4) + '</pre>');
|
||||
document.write('<h2>Profile</h2><pre>' + JSON.stringify(keycloak.profile(true), undefined, 4) + '</pre>');
|
||||
document.write('<h2>Contacts</h2><pre>' + keycloak.contacts(true) + '</pre>');
|
||||
} else {
|
||||
document.write('<a href="#" id="login" onclick="keycloak.login()">Login</a>');
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,139 +0,0 @@
|
|||
window.keycloak = (function () {
|
||||
var kc = {};
|
||||
var config = {
|
||||
clientId: null,
|
||||
clientSecret: null
|
||||
};
|
||||
|
||||
kc.init = function (c) {
|
||||
for (var prop in config) {
|
||||
if (c[prop]) {
|
||||
config[prop] = c[prop];
|
||||
}
|
||||
|
||||
if (!config[prop]) {
|
||||
throw new Error(prop + ' not defined');
|
||||
}
|
||||
}
|
||||
|
||||
loadToken();
|
||||
|
||||
if (kc.token) {
|
||||
kc.user = kc.tokenInfo.user_id;
|
||||
kc.authenticated = true;
|
||||
} else {
|
||||
kc.authenticated = false;
|
||||
kc.user = null;
|
||||
}
|
||||
}
|
||||
|
||||
kc.login = function () {
|
||||
var clientId = encodeURIComponent(config.clientId);
|
||||
var redirectUri = encodeURIComponent(window.location.href);
|
||||
var state = encodeURIComponent(createUUID());
|
||||
var scope = encodeURIComponent('https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.login');
|
||||
var url = 'https://accounts.google.com/o/oauth2/auth?response_type=token&client_id=' + clientId + '&redirect_uri=' + redirectUri
|
||||
+ '&state=' + state + '&scope=' + scope;
|
||||
|
||||
sessionStorage.state = state;
|
||||
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
function parseToken(token) {
|
||||
return JSON.parse(atob(token.split('.')[1]));
|
||||
}
|
||||
|
||||
kc.profile = function(header) {
|
||||
var url = 'https://www.googleapis.com/oauth2/v1/userinfo'
|
||||
|
||||
if (!header) {
|
||||
url = url + '?access_token=' + kc.token;
|
||||
}
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('GET', url, false);
|
||||
if (header) {
|
||||
http.setRequestHeader('Authorization', 'Bearer ' + kc.token);
|
||||
}
|
||||
|
||||
http.send();
|
||||
if (http.status == 200) {
|
||||
return JSON.parse(http.responseText);
|
||||
}
|
||||
}
|
||||
|
||||
kc.contacts = function(header) {
|
||||
var url = 'https://www.googleapis.com/plus/v1/people/me';
|
||||
|
||||
if (!header) {
|
||||
url = url + '?access_token=' + kc.token;
|
||||
}
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('GET', url, false);
|
||||
if (header) {
|
||||
http.setRequestHeader('Authorization', 'Bearer ' + kc.token);
|
||||
}
|
||||
|
||||
http.send();
|
||||
if (http.status == 200) {
|
||||
return http.responseText;
|
||||
}
|
||||
}
|
||||
|
||||
return kc;
|
||||
|
||||
function loadToken() {
|
||||
var params = {}
|
||||
var queryString = location.hash.substring(1)
|
||||
var regex = /([^&=]+)=([^&]*)/g, m;
|
||||
while (m = regex.exec(queryString)) {
|
||||
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
|
||||
}
|
||||
|
||||
var token = params['access_token'];
|
||||
var state = params['state'];
|
||||
|
||||
if (token && state === sessionStorage.state) {
|
||||
window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
|
||||
|
||||
kc.token = token;
|
||||
|
||||
var url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + token;
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('GET', url, false);
|
||||
|
||||
http.send();
|
||||
if (http.status == 200) {
|
||||
kc.tokenInfo = JSON.parse(http.responseText);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getQueryParam(name) {
|
||||
console.debug(window.location.hash);
|
||||
var params = window.location.hash.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
if (decodeURIComponent(p[0]) == name) {
|
||||
return p[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createUUID() {
|
||||
var s = [];
|
||||
var hexDigits = '0123456789abcdef';
|
||||
for (var i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
s[14] = '4';
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||
s[8] = s[13] = s[18] = s[23] = '-';
|
||||
var uuid = s.join('');
|
||||
return uuid;
|
||||
}
|
||||
})();
|
|
@ -1,222 +0,0 @@
|
|||
<<<<<<< Updated upstream
|
||||
window.keycloak = (function() {
|
||||
var kc = {};
|
||||
var config = null;
|
||||
|
||||
kc.init = function(c) {
|
||||
config = c;
|
||||
|
||||
var token = getTokenFromCode();
|
||||
if (token) {
|
||||
var t = parseToken(token);
|
||||
kc.user = t.prn;
|
||||
kc.authenticated = true;
|
||||
} else {
|
||||
kc.authenticated = false;
|
||||
}
|
||||
}
|
||||
|
||||
kc.login = function() {
|
||||
var clientId = encodeURIComponent(config.clientId);
|
||||
var redirectUri = encodeURIComponent(window.location.href);
|
||||
var state = encodeURIComponent(createUUID());
|
||||
var realm = encodeURIComponent(config.realm);
|
||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
|
||||
+ '&state=' + state;
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
return kc;
|
||||
|
||||
function parseToken(token) {
|
||||
return JSON.parse(atob(token.split('.')[1]));
|
||||
}
|
||||
|
||||
function getTokenFromCode() {
|
||||
var code = getQueryParam('code');
|
||||
if (code) {
|
||||
window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
|
||||
|
||||
var clientId = encodeURIComponent(config.clientId);
|
||||
var clientSecret = encodeURIComponent(config.clientSecret);
|
||||
var realm = encodeURIComponent(config.realm);
|
||||
|
||||
var params = 'code=' + code + '&client_id=' + config.clientId + '&password=' + config.clientSecret;
|
||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('POST', url, false);
|
||||
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
http.send(params);
|
||||
if (http.status == 200) {
|
||||
return JSON.parse(http.responseText)['access_token'];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getQueryParam(name) {
|
||||
var params = window.location.search.substring(1).split('&');
|
||||
for ( var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
if (decodeURIComponent(p[0]) == name) {
|
||||
return p[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createUUID() {
|
||||
var s = [];
|
||||
var hexDigits = '0123456789abcdef';
|
||||
for ( var i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
s[14] = '4';
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||
s[8] = s[13] = s[18] = s[23] = '-';
|
||||
var uuid = s.join('');
|
||||
return uuid;
|
||||
}
|
||||
=======
|
||||
window.keycloak = (function () {
|
||||
var kc = {};
|
||||
var config = {
|
||||
baseUrl : null,
|
||||
clientId : null,
|
||||
clientSecret: null,
|
||||
realm: null
|
||||
};
|
||||
|
||||
kc.init = function (c) {
|
||||
for (var prop in config) {
|
||||
if (c[prop]) {
|
||||
config[prop] = c[prop];
|
||||
}
|
||||
|
||||
if (!config[prop]) {
|
||||
throw new Error(prop + 'not defined');
|
||||
}
|
||||
}
|
||||
|
||||
var token = getTokenFromCode();
|
||||
if (token) {
|
||||
var t = parseToken(token);
|
||||
kc.user = t.prn;
|
||||
kc.authenticated = true;
|
||||
} else {
|
||||
kc.authenticated = false;
|
||||
}
|
||||
}
|
||||
|
||||
kc.login = function () {
|
||||
var clientId = encodeURIComponent(config.clientId);
|
||||
var redirectUri = encodeURIComponent(window.location.href);
|
||||
var realm = encodeURIComponent(config.realm);
|
||||
var state = encodeURIComponent(createUUID());
|
||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/login?response_type=code&client_id=' + clientId + '&redirect_uri=' + redirectUri
|
||||
+ '&state=' + state;
|
||||
|
||||
sessionStorage.state = state;
|
||||
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
return kc;
|
||||
|
||||
function parseToken(token) {
|
||||
var t = base64Decode(token.split('.')[1]);
|
||||
return JSON.parse(t);
|
||||
}
|
||||
|
||||
function getTokenFromCode() {
|
||||
var code = getQueryParam('code');
|
||||
var state = getQueryParam('state');
|
||||
|
||||
if (code) {
|
||||
if (state && state === sessionStorage.state) {
|
||||
window.history.replaceState({}, document.title, location.protocol + "//" + location.host + location.pathname);
|
||||
|
||||
var clientId = encodeURIComponent(config.clientId);
|
||||
var clientSecret = encodeURIComponent(config.clientSecret);
|
||||
var realm = encodeURIComponent(config.realm);
|
||||
|
||||
var params = 'code=' + code + '&client_id=' + clientId + '&password=' + clientSecret;
|
||||
var url = config.baseUrl + '/rest/realms/' + realm + '/tokens/access/codes'
|
||||
|
||||
var http = new XMLHttpRequest();
|
||||
http.open('POST', url, false);
|
||||
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
|
||||
http.send(params);
|
||||
if (http.status == 200) {
|
||||
return JSON.parse(http.responseText)['access_token'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getQueryParam(name) {
|
||||
var params = window.location.search.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
if (decodeURIComponent(p[0]) == name) {
|
||||
return p[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createUUID() {
|
||||
var s = [];
|
||||
var hexDigits = '0123456789abcdef';
|
||||
for (var i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
s[14] = '4';
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
|
||||
s[8] = s[13] = s[18] = s[23] = '-';
|
||||
var uuid = s.join('');
|
||||
return uuid;
|
||||
}
|
||||
|
||||
function base64Decode(data) {
|
||||
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
|
||||
ac = 0,
|
||||
dec = "",
|
||||
tmp_arr = [];
|
||||
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
data += '';
|
||||
|
||||
do {
|
||||
h1 = b64.indexOf(data.charAt(i++));
|
||||
h2 = b64.indexOf(data.charAt(i++));
|
||||
h3 = b64.indexOf(data.charAt(i++));
|
||||
h4 = b64.indexOf(data.charAt(i++));
|
||||
|
||||
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
|
||||
|
||||
o1 = bits >> 16 & 0xff;
|
||||
o2 = bits >> 8 & 0xff;
|
||||
o3 = bits & 0xff;
|
||||
|
||||
if (h3 == 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1);
|
||||
} else if (h4 == 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2);
|
||||
} else {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
|
||||
}
|
||||
} while (i < data.length);
|
||||
|
||||
dec = tmp_arr.join('');
|
||||
|
||||
return dec;
|
||||
}
|
||||
>>>>>>> Stashed changes
|
||||
})();
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
$.ajax('https://baas.kinvey.com/appdata/kid_PVD-jo1HqO');
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"id": "test",
|
||||
"realm": "test",
|
||||
"enabled": true,
|
||||
"tokenLifespan": 300,
|
||||
"accessCodeLifespan": 10,
|
||||
"accessCodeLifespanUserAction": 600,
|
||||
"sslNotRequired": true,
|
||||
"cookieLoginAllowed": true,
|
||||
"registrationAllowed": true,
|
||||
"resetPasswordAllowed": true,
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [ "password" ],
|
||||
"requiredApplicationCredentials": [ "password" ],
|
||||
"requiredOAuthClientCredentials": [ "password" ],
|
||||
"defaultRoles": [ "user" ],
|
||||
"users" : [
|
||||
{
|
||||
"username" : "test-user@localhost",
|
||||
"enabled": true,
|
||||
"email" : "test-user@localhost",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "Have User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Have Administrator privileges"
|
||||
}
|
||||
],
|
||||
"roleMappings": [
|
||||
{
|
||||
"username": "test-user@localhost",
|
||||
"roles": ["user"]
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
{
|
||||
"name": "test-app",
|
||||
"enabled": true,
|
||||
"adminUrl": "http://localhost:8081/app/logout",
|
||||
"useRealmMappings": true,
|
||||
"webOrigins": [ "http://localhost", "http://localhost:8000", "http://localhost:8080" ],
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "password"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 338 B |
|
@ -49,13 +49,30 @@ body {
|
|||
width: 100%;
|
||||
min-width: 120em;
|
||||
}
|
||||
.rcue-login-register .form-area.separator,
|
||||
.rcue-login-register .form-area.social,
|
||||
.rcue-login-register .form-area.social.separator {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 42.7em center;
|
||||
}
|
||||
.rcue-login-register .form-area.separator {
|
||||
background-image: url(img/login-register-separator.png);
|
||||
background-position: 43.2em center;
|
||||
}
|
||||
.rcue-login-register .form-area.social {
|
||||
background-image: url(img/login-register-social.png);
|
||||
}
|
||||
.rcue-login-register .form-area.social.separator {
|
||||
background-image: url(img/login-register-social-separator.png);
|
||||
}
|
||||
.rcue-login-register .background-area .section {
|
||||
float: left;
|
||||
padding: 0 4.5em 0 4.6em;
|
||||
width: auto;
|
||||
position: relative;
|
||||
}
|
||||
.rcue-login-register .background-area .separator .section {
|
||||
.rcue-login-register .background-area .separator .section,
|
||||
.rcue-login-register .background-area .social .section {
|
||||
padding-top: 1.5em;
|
||||
padding-bottom: 1.5em;
|
||||
}
|
||||
|
@ -65,15 +82,6 @@ body {
|
|||
.rcue-login-register .background-area .section:first-child {
|
||||
padding-right: 4.5em;
|
||||
}
|
||||
.rcue-login-register .form-area.separator {
|
||||
background-image: url(img/login-register-separator.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 43.2em center;
|
||||
}
|
||||
.rcue-login-register .form-area.social {
|
||||
background-image: url(img/login-register-social-separators.png);
|
||||
background-position: 39.6em center;
|
||||
}
|
||||
.rcue-login-register .section > p {
|
||||
font-size: 1.3em;
|
||||
margin-bottom: 1.53846153846154em;
|
||||
|
@ -120,7 +128,6 @@ body {
|
|||
.rcue-login-register form > div.aside-btn input[type="checkbox"] {
|
||||
margin-bottom: 0.54545454545455em;
|
||||
/* 6px */
|
||||
|
||||
}
|
||||
.rcue-login-register form > input[type="button"],
|
||||
.rcue-login-register form > input[type="submit"]{
|
||||
|
@ -137,13 +144,10 @@ body {
|
|||
top: -0.636363636363636em;
|
||||
}
|
||||
.rcue-login-register .feedback.bottom-left {
|
||||
left: 32.7em;
|
||||
left: 35.7em;
|
||||
top: -9.2em;
|
||||
min-width: 35em;
|
||||
}
|
||||
.rcue-login-register.reset .feedback.bottom-left {
|
||||
left: 35.7em;
|
||||
}
|
||||
.rcue-login-register input.error[type="text"],
|
||||
.rcue-login-register input.error[type="password"],
|
||||
.rcue-login-register input.error[type="email"] {
|
||||
|
|
|
@ -18,18 +18,20 @@
|
|||
<span>${role.description}</span>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
|
||||
<#list oauth.resourceRolesRequested?keys as resourceRole>
|
||||
<p class="instruction"><strong>${resourceRole}</strong> requests access to:</p>
|
||||
<ul>
|
||||
<#list oauth.resourceRolesRequested[resourceRole] as role>
|
||||
<li>
|
||||
<span>${role.description}</span>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</#list>
|
||||
<#list oauth.resourceRolesRequested?keys as resourceRole>
|
||||
<li>
|
||||
<strong>${resourceRole}</strong>
|
||||
<ul>
|
||||
<#list oauth.resourceRolesRequested[resourceRole] as role>
|
||||
<li>
|
||||
<span><#if role.description??>${role.description}<#else>${role.name}</#if></span>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
|
||||
<p class="terms">Keycloak Central Login and Google will use this information in accordance with their respective terms of service and privacy policies.</p>
|
||||
<form class="form-actions" action="${oauth.action}" method="POST">
|
||||
|
|
|
@ -39,4 +39,4 @@
|
|||
</div>
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
</@layout.registrationLayout>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -31,4 +33,9 @@ public interface ApplicationModel extends RoleContainerModel, RoleMapperModel, S
|
|||
|
||||
void setBaseUrl(String url);
|
||||
|
||||
List<String> getDefaultRoles();
|
||||
|
||||
void addDefaultRole(String name);
|
||||
|
||||
void updateDefaultRoles(String[] defaultRoles);
|
||||
}
|
||||
|
|
|
@ -12,5 +12,9 @@ public interface Constants {
|
|||
String IDENTITY_REQUESTER_ROLE = "KEYCLOAK_IDENTITY_REQUESTER";
|
||||
String WILDCARD_ROLE = "*";
|
||||
|
||||
String ACCOUNT_APPLICATION = "Account";
|
||||
String ACCOUNT_PROFILE_ROLE = "view-profile";
|
||||
String ACCOUNT_MANAGE_ROLE = "manage-account";
|
||||
|
||||
String ACCOUNT_MANAGEMENT_APPLICATION = "Account Management";
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
|
|||
|
||||
UserModel addUser(String username);
|
||||
|
||||
List<RoleModel> getDefaultRoles();
|
||||
List<String> getDefaultRoles();
|
||||
|
||||
void addDefaultRole(String name);
|
||||
|
||||
|
|
|
@ -272,4 +272,61 @@ public class ApplicationAdapter implements ApplicationModel {
|
|||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDefaultRoles() {
|
||||
Collection<RoleEntity> entities = application.getDefaultRoles();
|
||||
List<String> roles = new ArrayList<String>();
|
||||
if (entities == null) return roles;
|
||||
for (RoleEntity entity : entities) {
|
||||
roles.add(entity.getName());
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefaultRole(String name) {
|
||||
RoleModel role = getRole(name);
|
||||
if (role == null) {
|
||||
role = addRole(name);
|
||||
}
|
||||
Collection<RoleEntity> entities = application.getDefaultRoles();
|
||||
for (RoleEntity entity : entities) {
|
||||
if (entity.getId().equals(role.getId())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
entities.add(((RoleAdapter) role).getRole());
|
||||
em.flush();
|
||||
}
|
||||
|
||||
public static boolean contains(String str, String[] array) {
|
||||
for (String s : array) {
|
||||
if (str.equals(s)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultRoles(String[] defaultRoles) {
|
||||
Collection<RoleEntity> entities = application.getDefaultRoles();
|
||||
Set<String> already = new HashSet<String>();
|
||||
List<RoleEntity> remove = new ArrayList<RoleEntity>();
|
||||
for (RoleEntity rel : entities) {
|
||||
if (!contains(rel.getName(), defaultRoles)) {
|
||||
remove.add(rel);
|
||||
} else {
|
||||
already.add(rel.getName());
|
||||
}
|
||||
}
|
||||
for (RoleEntity entity : remove) {
|
||||
entities.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
for (String roleName : defaultRoles) {
|
||||
if (!already.contains(roleName)) {
|
||||
addDefaultRole(roleName);
|
||||
}
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,12 +457,12 @@ public class RealmAdapter implements RealmModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<RoleModel> getDefaultRoles() {
|
||||
public List<String> getDefaultRoles() {
|
||||
Collection<RoleEntity> entities = realm.getDefaultRoles();
|
||||
List<RoleModel> roles = new ArrayList<RoleModel>();
|
||||
List<String> roles = new ArrayList<String>();
|
||||
if (entities == null) return roles;
|
||||
for (RoleEntity entity : entities) {
|
||||
roles.add(new RoleAdapter(entity));
|
||||
roles.add(entity.getName());
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
@ -504,8 +504,8 @@ public class RealmAdapter implements RealmModel {
|
|||
}
|
||||
for (RoleEntity entity : remove) {
|
||||
entities.remove(entity);
|
||||
em.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
for (String roleName : defaultRoles) {
|
||||
if (!already.contains(roleName)) {
|
||||
addDefaultRole(roleName);
|
||||
|
@ -543,6 +543,7 @@ public class RealmAdapter implements RealmModel {
|
|||
em.persist(user);
|
||||
applicationData.setApplicationUser(user);
|
||||
applicationData.setName(name);
|
||||
applicationData.setEnabled(true);
|
||||
realm.getApplications().add(applicationData);
|
||||
em.persist(applicationData);
|
||||
em.flush();
|
||||
|
|
|
@ -33,6 +33,10 @@ public class ApplicationEntity {
|
|||
@JoinTable(name="APPLICATION_ROLES")
|
||||
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
|
||||
@JoinTable(name="APPLICATION_DEFAULT_ROLES")
|
||||
Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -84,4 +88,12 @@ public class ApplicationEntity {
|
|||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Collection<RoleEntity> getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(Collection<RoleEntity> defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,4 +281,19 @@ public class ApplicationAdapter implements ApplicationModel {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDefaultRoles() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefaultRole(String name) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultRoles(String[] defaultRoles) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,7 @@ import org.picketlink.idm.model.sample.SampleModel;
|
|||
import org.picketlink.idm.query.IdentityQuery;
|
||||
import org.picketlink.idm.query.RelationshipQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -257,4 +254,44 @@ public class ApplicationAdapter implements ApplicationModel {
|
|||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDefaultRoles() {
|
||||
if ( applicationData.getDefaultRoles() != null) {
|
||||
return Arrays.asList(applicationData.getDefaultRoles());
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefaultRole(String name) {
|
||||
if (getRole(name) == null) {
|
||||
addRole(name);
|
||||
}
|
||||
|
||||
String[] defaultRoles = applicationData.getDefaultRoles();
|
||||
if (defaultRoles == null) {
|
||||
defaultRoles = new String[1];
|
||||
} else {
|
||||
defaultRoles = Arrays.copyOf(defaultRoles, defaultRoles.length + 1);
|
||||
}
|
||||
defaultRoles[defaultRoles.length - 1] = name;
|
||||
|
||||
applicationData.setDefaultRoles(defaultRoles);
|
||||
updateApplication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDefaultRoles(String[] defaultRoles) {
|
||||
for (String name : defaultRoles) {
|
||||
if (getRole(name) == null) {
|
||||
addRole(name);
|
||||
}
|
||||
}
|
||||
|
||||
applicationData.setDefaultRoles(defaultRoles);
|
||||
updateApplication();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,13 +43,7 @@ import java.io.StringWriter;
|
|||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Meant to be a per-request object
|
||||
|
@ -767,17 +761,15 @@ public class RealmAdapter implements RealmModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<RoleModel> getDefaultRoles() {
|
||||
List<RoleModel> defaultRoleModels = new ArrayList<RoleModel>();
|
||||
if (realm.getDefaultRoles() != null) {
|
||||
for (String name : realm.getDefaultRoles()) {
|
||||
RoleAdapter role = getRole(name);
|
||||
if (role != null) {
|
||||
defaultRoleModels.add(role);
|
||||
}
|
||||
}
|
||||
public List<String> getDefaultRoles() {
|
||||
if (realm.getDefaultRoles() == null) return Collections.emptyList();
|
||||
List<String> list = new ArrayList<String>();
|
||||
for (String role : realm.getDefaultRoles()) {
|
||||
RoleModel model = getRole(role);
|
||||
if (model == null) throw new RuntimeException("default role missing");
|
||||
list.add(role);
|
||||
}
|
||||
return defaultRoleModels;
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,7 @@ public class ApplicationData extends AbstractPartition {
|
|||
private String managementUrl;
|
||||
private String baseUrl;
|
||||
private User resourceUser;
|
||||
private String[] defaultRoles;
|
||||
|
||||
public ApplicationData() {
|
||||
super(null);
|
||||
|
@ -76,4 +77,13 @@ public class ApplicationData extends AbstractPartition {
|
|||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
@AttributeProperty
|
||||
public String[] getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ public class ApplicationEntity implements Serializable {
|
|||
@AttributeValue
|
||||
private String baseUrl;
|
||||
|
||||
@AttributeValue
|
||||
private String[] defaultRoles;
|
||||
|
||||
@OneToOne
|
||||
@AttributeValue
|
||||
AccountTypeEntity resourceUser;
|
||||
|
@ -94,4 +97,13 @@ public class ApplicationEntity implements Serializable {
|
|||
public void setResourceUser(AccountTypeEntity resourceUser) {
|
||||
this.resourceUser = resourceUser;
|
||||
}
|
||||
|
||||
public String[] getDefaultRoles() {
|
||||
return defaultRoles;
|
||||
}
|
||||
|
||||
public void setDefaultRoles(String[] defaultRoles) {
|
||||
this.defaultRoles = defaultRoles;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,6 @@
|
|||
<module>api</module>
|
||||
<module>picketlink</module>
|
||||
<module>jpa</module>
|
||||
<module>mongo</module>
|
||||
<!-- <module>mongo</module> -->
|
||||
</modules>
|
||||
</project>
|
||||
|
|
4
pom.xml
|
@ -20,6 +20,7 @@
|
|||
<dom4j.version>1.6.1</dom4j.version>
|
||||
<mysql.version>5.1.25</mysql.version>
|
||||
<slf4j.version>1.6.1</slf4j.version>
|
||||
<jboss.version>7.1.1.Final</jboss.version>
|
||||
</properties>
|
||||
|
||||
<url>http://keycloak.org</url>
|
||||
|
@ -72,7 +73,8 @@
|
|||
<module>admin-ui</module>
|
||||
<module>examples</module>
|
||||
<module>testsuite</module>
|
||||
<!--<module>ui</module> -->
|
||||
<module>server</module>
|
||||
<module>dist</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
149
server/pom.xml
Executable file
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-alpha-1</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-server</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Keycloak Server</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>jose-jwt</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-ui</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-ui-styles</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-picketlink</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-jpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-social-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-social-google</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-social-twitter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-social-facebook</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-forms</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-simple-schema</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>jaxrs-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.161</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>auth-server</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
28
server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
Executable file
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.server;
|
||||
|
||||
import org.jboss.resteasy.jwt.JsonSerialization;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.ws.rs.core.Context;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class KeycloakServerApplication extends KeycloakApplication {
|
||||
|
||||
public KeycloakServerApplication(@Context ServletContext servletContext) {
|
||||
super(servletContext);
|
||||
KeycloakSession session = factory.createSession();
|
||||
session.getTransaction().begin();
|
||||
ApplianceBootstrap bootstrap = new ApplianceBootstrap();
|
||||
bootstrap.bootstrap(session);
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
}
|
33
server/src/main/resources/META-INF/persistence.xml
Executable file
|
@ -0,0 +1,33 @@
|
|||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||
version="1.0">
|
||||
<persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
|
||||
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
|
||||
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
|
||||
<class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
|
||||
<class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
<properties>
|
||||
<property name="hibernate.hbm2ddl.auto" value="create" />
|
||||
<property name="hibernate.show_sql" value="false" />
|
||||
<property name="hibernate.format_sql" value="false" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
</persistence>
|
10
server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
Executable file
|
@ -0,0 +1,10 @@
|
|||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
|
||||
<dependencies>
|
||||
<module name="org.jboss.resteasy.jose-jwt"/>
|
||||
<module name="org.jboss.resteasy.resteasy-crypto"/>
|
||||
<module name="org.bouncycastle"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
39
server/src/main/webapp/WEB-INF/web.xml
Executable file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>auth-server</module-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Resteasy</servlet-name>
|
||||
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher</servlet-class>
|
||||
<init-param>
|
||||
<param-name>javax.ws.rs.Application</param-name>
|
||||
<param-value>org.keycloak.server.KeycloakServerApplication</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>resteasy.servlet.mapping.prefix</param-name>
|
||||
<param-value>/rest</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
|
||||
<filter>
|
||||
<filter-name>Keycloak Session Management</filter-name>
|
||||
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>Keycloak Session Management</filter-name>
|
||||
<url-pattern>/rest/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Resteasy</servlet-name>
|
||||
<url-pattern>/rest/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
|
@ -48,26 +48,53 @@ public class EmailSender {
|
|||
|
||||
private static final Logger log = Logger.getLogger(EmailSender.class);
|
||||
|
||||
private Properties properties;
|
||||
private Map<String, String> config;
|
||||
|
||||
public EmailSender(Map<String, String> config) {
|
||||
properties = new Properties();
|
||||
for (Entry<String, String> e : config.entrySet()) {
|
||||
properties.put("mail.smtp." + e.getKey(), e.getValue());
|
||||
}
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public void send(String address, String subject, String body) throws MessagingException {
|
||||
Session session = Session.getInstance(properties);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("mail.smtp.host", config.get("host"));
|
||||
|
||||
boolean auth = "true".equals(config.get("auth"));
|
||||
boolean ssl = "true".equals(config.get("ssl"));
|
||||
boolean starttls = "true".equals(config.get("starttls"));
|
||||
|
||||
if (config.containsKey("port")) {
|
||||
props.setProperty("mail.smtp.port", config.get("port"));
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
props.put("mail.smtp.auth", "true");
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
props.put("mail.smtp.socketFactory.port", config.get("port"));
|
||||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
}
|
||||
|
||||
if (starttls) {
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
}
|
||||
|
||||
String from = config.get("from");
|
||||
|
||||
Session session = Session.getInstance(props);
|
||||
|
||||
Message msg = new MimeMessage(session);
|
||||
msg.setFrom(new InternetAddress(properties.getProperty("mail.smtp.from")));
|
||||
msg.setFrom(new InternetAddress(from));
|
||||
msg.setSubject(subject);
|
||||
msg.setText(body);
|
||||
msg.saveChanges();
|
||||
|
||||
Transport transport = session.getTransport("smtp");
|
||||
transport.connect(properties.getProperty("mail.smtp.user"), properties.getProperty("mail.smtp.password"));
|
||||
if (auth) {
|
||||
transport.connect(config.get("user"), config.get("password"));
|
||||
} else {
|
||||
transport.connect();
|
||||
}
|
||||
transport.sendMessage(msg, new InternetAddress[] { new InternetAddress(address) });
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,11 @@ public class ApplicationManager {
|
|||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceRep.getDefaultRoles() != null) {
|
||||
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
||||
}
|
||||
|
||||
if (resourceRep.getRoleMappings() != null) {
|
||||
for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
|
||||
UserModel user = realm.getUser(mapping.getUsername());
|
||||
|
@ -114,6 +119,10 @@ public class ApplicationManager {
|
|||
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
|
||||
resource.updateApplication();
|
||||
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
resource.updateDefaultRoles(rep.getDefaultRoles());
|
||||
}
|
||||
|
||||
List<String> redirectUris = rep.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
|
||||
|
@ -144,6 +153,10 @@ public class ApplicationManager {
|
|||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (!applicationModel.getDefaultRoles().isEmpty()) {
|
||||
rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
|
||||
}
|
||||
|
||||
return rep;
|
||||
|
||||
}
|
||||
|
|
|
@ -56,24 +56,27 @@ public class AuthenticationManager {
|
|||
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
||||
URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
|
||||
String cookiePath = uri.getPath();
|
||||
return createLoginCookie(realm, user, cookieName, cookiePath);
|
||||
return createLoginCookie(realm, user, null, cookieName, cookiePath);
|
||||
}
|
||||
|
||||
public NewCookie createSaasIdentityCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
|
||||
String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
|
||||
URI uri = SaasService.saasCookiePath(uriInfo).build();
|
||||
String cookiePath = uri.getPath();
|
||||
return createLoginCookie(realm, user, cookieName, cookiePath);
|
||||
return createLoginCookie(realm, user, null, cookieName, cookiePath);
|
||||
}
|
||||
|
||||
public NewCookie createAccountIdentityCookie(RealmModel realm, UserModel user, URI uri) {
|
||||
public NewCookie createAccountIdentityCookie(RealmModel realm, UserModel user, UserModel client, URI uri) {
|
||||
String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
|
||||
String cookiePath = uri.getPath();
|
||||
return createLoginCookie(realm, user, cookieName, cookiePath);
|
||||
return createLoginCookie(realm, user, client, cookieName, cookiePath);
|
||||
}
|
||||
|
||||
protected NewCookie createLoginCookie(RealmModel realm, UserModel user, String cookieName, String cookiePath) {
|
||||
protected NewCookie createLoginCookie(RealmModel realm, UserModel user, UserModel client, String cookieName, String cookiePath) {
|
||||
SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
|
||||
if (client != null) {
|
||||
identityToken.issuedFor(client.getLoginName());
|
||||
}
|
||||
String encoded = encodeToken(realm, identityToken);
|
||||
boolean secureOnly = !realm.isSslNotRequired();
|
||||
logger.debug("creatingLoginCookie - name: {0} path: {1}", cookieName, cookiePath);
|
||||
|
@ -127,15 +130,17 @@ public class AuthenticationManager {
|
|||
|
||||
public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
||||
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
|
||||
Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
|
||||
return auth != null ? auth.getUser() : null;
|
||||
}
|
||||
|
||||
public UserModel authenticateSaasIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
|
||||
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
|
||||
Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
|
||||
return auth != null ? auth.getUser() : null;
|
||||
}
|
||||
|
||||
public UserModel authenticateAccountIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
public Auth authenticateAccountIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
|
||||
return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
|
||||
}
|
||||
|
@ -144,11 +149,19 @@ public class AuthenticationManager {
|
|||
UserModel user = authenticateSaasIdentityCookie(realm, uriInfo, headers);
|
||||
if (user != null) return user;
|
||||
|
||||
Auth auth = authenticateBearerToken(realm, headers);
|
||||
return auth != null ? auth.getUser() : null;
|
||||
}
|
||||
|
||||
public Auth authenticateAccountIdentity(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
|
||||
Auth auth = authenticateAccountIdentityCookie(realm, uriInfo, headers);
|
||||
if (auth != null) return auth;
|
||||
|
||||
return authenticateBearerToken(realm, headers);
|
||||
}
|
||||
|
||||
|
||||
protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
|
||||
protected Auth authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
|
||||
Cookie cookie = headers.getCookies().get(cookieName);
|
||||
if (cookie == null) {
|
||||
logger.debug("authenticateCookie could not find cookie: {0}", cookieName);
|
||||
|
@ -163,13 +176,28 @@ public class AuthenticationManager {
|
|||
expireIdentityCookie(realm, uriInfo);
|
||||
return null;
|
||||
}
|
||||
|
||||
Auth auth = new Auth(token);
|
||||
|
||||
UserModel user = realm.getUser(token.getPrincipal());
|
||||
if (user == null || !user.isEnabled()) {
|
||||
logger.debug("Unknown user in identity cookie");
|
||||
expireIdentityCookie(realm, uriInfo);
|
||||
return null;
|
||||
}
|
||||
return user;
|
||||
auth.setUser(user);
|
||||
|
||||
if (token.getIssuedFor() != null) {
|
||||
UserModel client = realm.getUser(token.getIssuedFor());
|
||||
if (client == null || !client.isEnabled()) {
|
||||
logger.debug("Unknown client in identity cookie");
|
||||
expireIdentityCookie(realm, uriInfo);
|
||||
return null;
|
||||
}
|
||||
auth.setClient(client);
|
||||
}
|
||||
|
||||
return auth;
|
||||
} catch (VerificationException e) {
|
||||
logger.debug("Failed to verify identity cookie", e);
|
||||
expireIdentityCookie(realm, uriInfo);
|
||||
|
@ -177,11 +205,11 @@ public class AuthenticationManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
public UserModel authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
|
||||
public Auth authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
|
||||
String tokenString = null;
|
||||
String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader == null) {
|
||||
throw new NotAuthorizedException("Bearer");
|
||||
return null;
|
||||
} else {
|
||||
String[] split = authHeader.trim().split("\\s+");
|
||||
if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
|
||||
|
@ -195,11 +223,24 @@ public class AuthenticationManager {
|
|||
if (!token.isActive()) {
|
||||
throw new NotAuthorizedException("token_expired");
|
||||
}
|
||||
|
||||
Auth auth = new Auth(token);
|
||||
|
||||
UserModel user = realm.getUser(token.getPrincipal());
|
||||
if (user == null || !user.isEnabled()) {
|
||||
throw new NotAuthorizedException("invalid_user");
|
||||
}
|
||||
return user;
|
||||
auth.setUser(user);
|
||||
|
||||
if (token.getIssuedFor() != null) {
|
||||
UserModel client = realm.getUser(token.getIssuedFor());
|
||||
if (client == null || !client.isEnabled()) {
|
||||
throw new NotAuthorizedException("invalid_user");
|
||||
}
|
||||
auth.setClient(client);
|
||||
}
|
||||
|
||||
return auth;
|
||||
} catch (VerificationException e) {
|
||||
logger.error("Failed to verify token", e);
|
||||
throw new NotAuthorizedException("invalid_token");
|
||||
|
@ -271,4 +312,34 @@ public class AuthenticationManager {
|
|||
SUCCESS, ACCOUNT_DISABLED, ACTIONS_REQUIRED, INVALID_USER, INVALID_CREDENTIALS, MISSING_PASSWORD, MISSING_TOTP, FAILED
|
||||
}
|
||||
|
||||
public static class Auth {
|
||||
private SkeletonKeyToken token;
|
||||
private UserModel user;
|
||||
private UserModel client;
|
||||
|
||||
public Auth(SkeletonKeyToken token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public SkeletonKeyToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public UserModel getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public UserModel getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
void setUser(UserModel user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
void setClient(UserModel client) {
|
||||
this.client = client;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public class RealmManager {
|
|||
realm.updateRequiredApplicationCredentials(rep.getRequiredApplicationCredentials());
|
||||
}
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
realm.updateDefaultRoles(rep.getDefaultRoles());
|
||||
realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
|
||||
}
|
||||
|
||||
if (rep.getAccountManagement() != null && rep.getAccountManagement()) {
|
||||
|
@ -129,9 +129,11 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
private void enableAccountManagement(RealmModel realm) {
|
||||
ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_APPLICATION);
|
||||
if (application == null) {
|
||||
application = realm.addApplication(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
application = realm.addApplication(Constants.ACCOUNT_APPLICATION);
|
||||
application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE);
|
||||
application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE);
|
||||
|
||||
UserCredentialModel password = new UserCredentialModel();
|
||||
password.setType(UserCredentialModel.PASSWORD);
|
||||
|
@ -146,7 +148,7 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
private void disableAccountManagement(RealmModel realm) {
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
if (application != null) {
|
||||
application.setEnabled(false); // TODO Should we delete the application instead?
|
||||
}
|
||||
|
@ -410,9 +412,11 @@ public class RealmManager {
|
|||
rep.setLastName(user.getLastName());
|
||||
rep.setFirstName(user.getFirstName());
|
||||
rep.setEmail(user.getEmail());
|
||||
Map<String, String> attrs = new HashMap<String, String>();
|
||||
attrs.putAll(user.getAttributes());
|
||||
rep.setAttributes(attrs);
|
||||
if (user.getAttributes() != null && !user.getAttributes().isEmpty()) {
|
||||
Map<String, String> attrs = new HashMap<String, String>();
|
||||
attrs.putAll(user.getAttributes());
|
||||
rep.setAttributes(attrs);
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
@ -444,16 +448,14 @@ public class RealmManager {
|
|||
rep.setSmtpServer(realm.getSmtpConfig());
|
||||
rep.setSocialProviders(realm.getSocialConfig());
|
||||
|
||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
rep.setAccountManagement(accountManagementApplication != null && accountManagementApplication.isEnabled());
|
||||
|
||||
List<RoleModel> defaultRoles = realm.getDefaultRoles();
|
||||
if (defaultRoles.size() > 0) {
|
||||
String[] d = new String[defaultRoles.size()];
|
||||
for (int i = 0; i < d.length; i++) {
|
||||
d[i] = defaultRoles.get(i).getName();
|
||||
}
|
||||
rep.setDefaultRoles(d);
|
||||
List<String> defaultRoles = realm.getDefaultRoles();
|
||||
if (!defaultRoles.isEmpty()) {
|
||||
List<String> roleStrings = new ArrayList<String>();
|
||||
roleStrings.addAll(defaultRoles);
|
||||
rep.setDefaultRoles(roleStrings);
|
||||
}
|
||||
|
||||
List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
package org.keycloak.social;
|
||||
package org.keycloak.services.managers;
|
||||
|
||||
import org.keycloak.social.RequestDetails;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
|
@ -15,6 +15,7 @@ import org.keycloak.representations.SkeletonKeyToken;
|
|||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -51,12 +52,16 @@ public class TokenManager {
|
|||
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
|
||||
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
|
||||
Set<String> realmMapping = realm.getRoleMappingValues(user);
|
||||
realmMapping.addAll(realm.getDefaultRoles());
|
||||
|
||||
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
|
||||
Set<String> scope = realm.getScopeMappingValues(client);
|
||||
if (scope.size() > 0) {
|
||||
Set<String> scopeRequest = null;
|
||||
if (scopeMap != null) {
|
||||
if (scopeRequest == null) {
|
||||
scopeRequest = new HashSet<String>();
|
||||
}
|
||||
scopeRequest.addAll(scopeMap.get("realm"));
|
||||
if (scopeRequest.contains(Constants.WILDCARD_ROLE)) scopeRequest = null;
|
||||
}
|
||||
|
@ -71,11 +76,15 @@ public class TokenManager {
|
|||
}
|
||||
for (ApplicationModel resource : realm.getApplications()) {
|
||||
Set<String> mapping = resource.getRoleMappingValues(user);
|
||||
mapping.addAll(resource.getDefaultRoles());
|
||||
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
|
||||
Set<String> scope = resource.getScopeMappingValues(client);
|
||||
if (scope.size() > 0) {
|
||||
Set<String> scopeRequest = null;
|
||||
if (scopeMap != null) {
|
||||
if (scopeRequest == null) {
|
||||
scopeRequest = new HashSet<String>();
|
||||
}
|
||||
scopeRequest.addAll(scopeMap.get(resource.getName()));
|
||||
if (scopeRequest.contains(Constants.WILDCARD_ROLE)) scopeRequest = null;
|
||||
}
|
||||
|
|
|
@ -27,15 +27,13 @@ import org.jboss.resteasy.logging.Logger;
|
|||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.AbstractOAuthClient;
|
||||
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.*;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
|
@ -44,23 +42,11 @@ import org.keycloak.services.resources.flows.Pages;
|
|||
import org.keycloak.services.resources.flows.Urls;
|
||||
import org.keycloak.services.validation.Validation;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.ForbiddenException;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.*;
|
||||
import javax.ws.rs.ext.Providers;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -98,18 +84,42 @@ public class AccountService {
|
|||
}
|
||||
|
||||
private Response forwardToPage(String path, String template) {
|
||||
UserModel user = getUser(false);
|
||||
if (user != null) {
|
||||
return Flows.forms(realm, request, uriInfo).setUser(user).forwardToForm(template);
|
||||
AuthenticationManager.Auth auth = getAuth(false);
|
||||
if (auth != null) {
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
return Flows.forms(realm, request, uriInfo).setUser(auth.getUser()).forwardToForm(template);
|
||||
} else {
|
||||
return login(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Path("")
|
||||
private Response noAccess() {
|
||||
return Flows.forms(realm, request, uriInfo).setError("No access").forwardToErrorPage();
|
||||
}
|
||||
|
||||
@Path("/")
|
||||
@OPTIONS
|
||||
public Response accountPreflight() {
|
||||
return Cors.add(request, Response.ok()).auth().preflight().build();
|
||||
}
|
||||
|
||||
@Path("/")
|
||||
@GET
|
||||
public Response accountPage() {
|
||||
return forwardToPage(null, Pages.ACCOUNT);
|
||||
List<MediaType> types = headers.getAcceptableMediaTypes();
|
||||
if (types.contains(MediaType.WILDCARD_TYPE) || (types.contains(MediaType.TEXT_HTML_TYPE))) {
|
||||
return forwardToPage(null, Pages.ACCOUNT);
|
||||
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) {
|
||||
return Response.status(Response.Status.FORBIDDEN).build();
|
||||
}
|
||||
return Cors.add(request, Response.ok(RealmManager.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
|
||||
} else {
|
||||
return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@Path("social")
|
||||
|
@ -136,12 +146,16 @@ public class AccountService {
|
|||
return forwardToPage("access", Pages.ACCESS);
|
||||
}
|
||||
|
||||
@Path("")
|
||||
@Path("/")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
|
||||
UserModel user = getUser(true);
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
String error = Validation.validateUpdateProfileForm(formData);
|
||||
if (error != null) {
|
||||
|
@ -159,7 +173,13 @@ public class AccountService {
|
|||
@Path("totp-remove")
|
||||
@GET
|
||||
public Response processTotpRemove() {
|
||||
UserModel user = getUser(true);
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
user.setTotp(false);
|
||||
return Flows.forms(realm, request, uriInfo).setError("successTotpRemoved").setErrorType(FormFlows.MessageType.SUCCESS)
|
||||
.setUser(user).forwardToTotp();
|
||||
|
@ -169,7 +189,12 @@ public class AccountService {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
|
||||
UserModel user = getUser(true);
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
String totp = formData.getFirst("totp");
|
||||
String totpSecret = formData.getFirst("totpSecret");
|
||||
|
@ -196,7 +221,12 @@ public class AccountService {
|
|||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
|
||||
UserModel user = getUser(true);
|
||||
AuthenticationManager.Auth auth = getAuth(true);
|
||||
if (!hasAccess(auth)) {
|
||||
return noAccess();
|
||||
}
|
||||
|
||||
UserModel user = auth.getUser();
|
||||
|
||||
FormFlows forms = Flows.forms(realm, request, uriInfo).setUser(user);
|
||||
|
||||
|
@ -297,7 +327,7 @@ public class AccountService {
|
|||
}
|
||||
URI redirectUri = redirectBuilder.build(realm.getId());
|
||||
|
||||
NewCookie cookie = authManager.createAccountIdentityCookie(realm, accessCode.getUser(), Urls.accountBase(uriInfo.getBaseUri()).build(realm.getId()));
|
||||
NewCookie cookie = authManager.createAccountIdentityCookie(realm, accessCode.getUser(), client, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getId()));
|
||||
return Response.status(302).cookie(cookie).location(redirectUri).build();
|
||||
} finally {
|
||||
authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getPath());
|
||||
|
@ -319,7 +349,7 @@ public class AccountService {
|
|||
String authUrl = Urls.realmLoginPage(uriInfo.getBaseUri(), realm.getId()).toString();
|
||||
oauth.setAuthUrl(authUrl);
|
||||
|
||||
oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
oauth.setClientId(Constants.ACCOUNT_APPLICATION);
|
||||
|
||||
URI accountUri = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect").build(realm.getId());
|
||||
|
||||
|
@ -327,11 +357,42 @@ public class AccountService {
|
|||
return oauth.redirect(uriInfo, accountUri.toString(), path);
|
||||
}
|
||||
|
||||
private UserModel getUser(boolean required) {
|
||||
UserModel user = authManager.authenticateAccountIdentityCookie(realm, uriInfo, headers);
|
||||
if (user == null && required) {
|
||||
private AuthenticationManager.Auth getAuth(boolean error) {
|
||||
AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers);
|
||||
if (auth == null && error) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
return user;
|
||||
return auth;
|
||||
}
|
||||
|
||||
private boolean hasAccess(AuthenticationManager.Auth auth) {
|
||||
return hasAccess(auth, null);
|
||||
}
|
||||
|
||||
private boolean hasAccess(AuthenticationManager.Auth auth, String role) {
|
||||
UserModel client = auth.getClient();
|
||||
if (realm.hasRole(client, Constants.APPLICATION_ROLE)) {
|
||||
// Tokens from cookies don't have roles
|
||||
if (hasRole(client, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(client, role))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
SkeletonKeyToken.Access access = auth.getToken().getResourceAccess(application.getName());
|
||||
if (access != null) {
|
||||
if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE) || (role != null && access.isUserInRole(role))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasRole(UserModel user, String role) {
|
||||
if (application.getDefaultRoles().contains(role)) {
|
||||
return true;
|
||||
}
|
||||
return application.hasRole(user, role);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,19 +1,37 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class Cors {
|
||||
|
||||
public static final long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
|
||||
public static final String DEFAULT_ALLOW_METHODS = "GET, OPTIONS";
|
||||
|
||||
public static final String ORIGIN = "Origin";
|
||||
|
||||
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
||||
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
|
||||
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
||||
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
||||
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
|
||||
|
||||
private HttpRequest request;
|
||||
private ResponseBuilder response;
|
||||
private Set<String> allowedOrigins;
|
||||
private String[] allowedMethods;
|
||||
|
||||
private boolean preflight;
|
||||
private boolean auth;
|
||||
|
||||
public Cors(HttpRequest request, ResponseBuilder response) {
|
||||
this.request = request;
|
||||
|
@ -24,18 +42,60 @@ public class Cors {
|
|||
return new Cors(request, response);
|
||||
}
|
||||
|
||||
public Cors allowedOrigins(Set<String> allowedOrigins) {
|
||||
this.allowedOrigins = allowedOrigins;
|
||||
public Cors preflight() {
|
||||
preflight = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cors auth() {
|
||||
auth = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cors allowedOrigins(UserModel client) {
|
||||
if (client != null) {
|
||||
allowedOrigins = client.getWebOrigins();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Cors allowedMethods(String... allowedMethods) {
|
||||
this.allowedMethods = allowedMethods;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Response build() {
|
||||
String origin = request.getHttpHeaders().getHeaderString("Origin");
|
||||
if (origin == null || allowedOrigins == null || (!allowedOrigins.contains(origin))) {
|
||||
String origin = request.getHttpHeaders().getHeaderString(ORIGIN);
|
||||
if (origin == null) {
|
||||
return response.build();
|
||||
}
|
||||
|
||||
response.header("Access-Control-Allow-Origin", origin);
|
||||
if (!preflight && (allowedOrigins == null || !allowedOrigins.contains(origin))) {
|
||||
return response.build();
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
|
||||
if (allowedMethods != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < allowedMethods.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(allowedMethods[i]);
|
||||
}
|
||||
response.header(ACCESS_CONTROL_ALLOW_METHODS, sb.toString());
|
||||
} else {
|
||||
response.header(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
|
||||
if (auth) {
|
||||
response.header(ACCESS_CONTROL_ALLOW_HEADERS, "Authorization");
|
||||
}
|
||||
|
||||
response.header(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
|
||||
|
||||
return response.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package org.keycloak.services.resources;
|
|||
import org.keycloak.SkeletonKeyContextResolver;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.services.managers.SocialRequestManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.utils.PropertiesManager;
|
||||
import org.keycloak.social.SocialRequestManager;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.servlet.ServletContext;
|
||||
|
|
|
@ -69,7 +69,7 @@ public class RealmsResource {
|
|||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
|
||||
ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
if (application == null || !application.isEnabled()) {
|
||||
logger.debug("account management not enabled");
|
||||
throw new NotFoundException();
|
||||
|
|
|
@ -39,12 +39,11 @@ import org.keycloak.services.resources.flows.Urls;
|
|||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.RequestDetails;
|
||||
import org.keycloak.social.RequestDetailsBuilder;
|
||||
import org.keycloak.social.SocialConstants;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
import org.keycloak.social.SocialRequestManager;
|
||||
import org.keycloak.services.managers.SocialRequestManager;
|
||||
import org.keycloak.social.SocialUser;
|
||||
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
|
@ -181,19 +180,12 @@ public class SocialResource {
|
|||
}
|
||||
|
||||
realm.addSocialLink(user, socialLink);
|
||||
|
||||
for (RoleModel role : realm.getDefaultRoles()) {
|
||||
realm.grantRole(user, role);
|
||||
}
|
||||
} else {
|
||||
// Redirect user to registration screen with prefilled data from social provider
|
||||
MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
|
||||
|
||||
RequestDetailsBuilder reqDetailsBuilder = RequestDetailsBuilder.createFromRequestDetails(requestData);
|
||||
reqDetailsBuilder.putSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK, socialLink);
|
||||
|
||||
String requestId = UUID.randomUUID().toString();
|
||||
socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
|
||||
socialRequestManager.addRequest(requestId, RequestDetails.create(requestData).build());
|
||||
boolean secureOnly = !realm.isSslNotRequired();
|
||||
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
||||
logger.debug("creating cookie for social registration - name: {0} path: {1}", SocialConstants.SOCIAL_REGISTRATION_COOKIE,
|
||||
|
@ -241,7 +233,7 @@ public class SocialResource {
|
|||
try {
|
||||
AuthRequest authRequest = provider.getAuthUrl(config);
|
||||
|
||||
RequestDetails socialRequest = RequestDetailsBuilder.create(providerId)
|
||||
RequestDetails socialRequest = RequestDetails.create(providerId)
|
||||
.putSocialAttributes(authRequest.getAttributes()).putClientAttribute("realmId", realmId)
|
||||
.putClientAttribute("clientId", clientId).putClientAttribute("scope", scope)
|
||||
.putClientAttribute("state", state).putClientAttribute("redirectUri", redirectUri).build();
|
||||
|
@ -285,7 +277,6 @@ public class SocialResource {
|
|||
String scope = requestData.getClientAttribute("scope");
|
||||
String state = requestData.getClientAttribute("state");
|
||||
String redirectUri = requestData.getClientAttribute("redirectUri");
|
||||
SocialLinkModel socialLink = (SocialLinkModel)requestData.getSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK);
|
||||
|
||||
Response response1 = tokenService.processRegisterImpl(clientId, scope, state, redirectUri, formData, true);
|
||||
|
||||
|
@ -301,7 +292,7 @@ public class SocialResource {
|
|||
// Normally shouldn't happen
|
||||
throw new IllegalStateException("User " + username + " not found in the realm");
|
||||
}
|
||||
realm.addSocialLink(user, socialLink);
|
||||
realm.addSocialLink(user, new SocialLinkModel(requestData.getProviderId(), username));
|
||||
|
||||
// Expire cookie and invalidate requestData
|
||||
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
||||
|
|
|
@ -323,10 +323,6 @@ public class TokenService {
|
|||
realm.updateCredential(user, credentials);
|
||||
}
|
||||
|
||||
for (RoleModel role : realm.getDefaultRoles()) {
|
||||
realm.grantRole(user, role);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -427,7 +423,7 @@ public class TokenService {
|
|||
logger.debug("accessRequest SUCCESS");
|
||||
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
|
||||
|
||||
return Cors.add(request, Response.ok(res)).allowedOrigins(client.getWebOrigins()).build();
|
||||
return Cors.add(request, Response.ok(res)).allowedOrigins(client).build();
|
||||
}
|
||||
|
||||
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
|
||||
|
@ -468,7 +464,7 @@ public class TokenService {
|
|||
}
|
||||
UserModel client = realm.getUser(clientId);
|
||||
if (client == null) {
|
||||
logger.warn("Unknown login requester.");
|
||||
logger.warn("Unknown login requester: " + clientId);
|
||||
oauth.forwardToSecurityFailure("Unknown login requester.");
|
||||
transaction.rollback();
|
||||
return null;
|
||||
|
|
|
@ -55,7 +55,7 @@ public class EmailSenderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void sendMail() throws AddressException, MessagingException, IOException {
|
||||
public void sendMail() throws MessagingException, IOException {
|
||||
emailSender.send("test@test.com", "Test subject", "Test body");
|
||||
|
||||
MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
|
||||
|
|
|
@ -77,7 +77,7 @@ public class AdapterTest extends AbstractKeycloakTest {
|
|||
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
||||
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
||||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName());
|
||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -106,7 +106,7 @@ public class AdapterTest extends AbstractKeycloakTest {
|
|||
Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
|
||||
Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
|
||||
Assert.assertEquals(1, realmModel.getDefaultRoles().size());
|
||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName());
|
||||
Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
|
||||
|
||||
String id = realmModel.getId();
|
||||
System.out.println("id: " + id);
|
||||
|
|
|
@ -45,6 +45,8 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
|
|||
application.setName("app-name");
|
||||
application.addRole("role-1");
|
||||
application.addRole("role-2");
|
||||
application.addDefaultRole("role-1");
|
||||
application.addDefaultRole("role-2");
|
||||
|
||||
application.getApplicationUser().addRedirectUri("redirect-1");
|
||||
application.getApplicationUser().addRedirectUri("redirect-2");
|
||||
|
@ -83,6 +85,7 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
|
|||
Assert.assertEquals(expected.getName(), actual.getName());
|
||||
Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
|
||||
Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
|
||||
Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
|
||||
|
||||
UserModel auser = actual.getApplicationUser();
|
||||
UserModel euser = expected.getApplicationUser();
|
||||
|
|
|
@ -85,7 +85,7 @@ public class ModelTest extends AbstractKeycloakServerTest {
|
|||
Assert.assertEquals(expected.getPublicKeyPem(), actual.getPublicKeyPem());
|
||||
Assert.assertEquals(expected.getPrivateKeyPem(), actual.getPrivateKeyPem());
|
||||
|
||||
assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
|
||||
Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
|
||||
|
||||
Assert.assertEquals(expected.getSmtpConfig(), actual.getSmtpConfig());
|
||||
Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig());
|
||||
|
|
|
@ -28,11 +28,11 @@ import java.util.Map;
|
|||
*/
|
||||
public class AuthCallback {
|
||||
|
||||
private Map<String, Object> attributes;
|
||||
private Map<String, String> attributes;
|
||||
|
||||
private Map<String, String[]> queryParams;
|
||||
|
||||
public AuthCallback(Map<String, Object> attributes, Map<String, String[]> queryParams) {
|
||||
public AuthCallback(Map<String, String> attributes, Map<String, String[]> queryParams) {
|
||||
this.attributes = attributes;
|
||||
this.queryParams = queryParams;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
*/
|
||||
package org.keycloak.social;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -33,9 +35,17 @@ public class AuthRequest {
|
|||
|
||||
private URI authUri;
|
||||
|
||||
private Map<String, Object> attributes;
|
||||
private Map<String, String> attributes;
|
||||
|
||||
AuthRequest(String id, URI authUri, Map<String, Object> attributes) {
|
||||
public static AuthRequestBuilder create(String id, String path) {
|
||||
AuthRequestBuilder req = new AuthRequestBuilder();
|
||||
req.id = id;
|
||||
req.b = UriBuilder.fromUri(path);
|
||||
req.attributes = new HashMap<String, String>();
|
||||
return req;
|
||||
}
|
||||
|
||||
private AuthRequest(String id, URI authUri, Map<String, String> attributes) {
|
||||
this.id = id;
|
||||
this.authUri = authUri;
|
||||
this.attributes = attributes;
|
||||
|
@ -49,8 +59,35 @@ public class AuthRequest {
|
|||
return authUri;
|
||||
}
|
||||
|
||||
public Map<String, Object> getAttributes() {
|
||||
public Map<String, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public static class AuthRequestBuilder {
|
||||
|
||||
private UriBuilder b;
|
||||
|
||||
private Map<String, String> attributes;
|
||||
|
||||
private String id;
|
||||
|
||||
private AuthRequestBuilder() {
|
||||
}
|
||||
|
||||
public AuthRequestBuilder setQueryParam(String name, String value) {
|
||||
b.queryParam(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder setAttribute(String name, String value) {
|
||||
attributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest build() {
|
||||
return new AuthRequest(id, b.build(), attributes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source.
|
||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
||||
* as indicated by the @author tags. See the copyright.txt file in the
|
||||
* distribution for a full listing of individual contributors.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
package org.keycloak.social;
|
||||
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuthRequestBuilder {
|
||||
|
||||
private UriBuilder b;
|
||||
|
||||
private Map<String, Object> attributes;
|
||||
|
||||
private String id;
|
||||
|
||||
private AuthRequestBuilder() {
|
||||
}
|
||||
|
||||
public static AuthRequestBuilder create(String id, String path) {
|
||||
AuthRequestBuilder req = new AuthRequestBuilder();
|
||||
req.id = id;
|
||||
req.b = UriBuilder.fromUri(path);
|
||||
req.attributes = new HashMap<String, Object>();
|
||||
return req;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder setQueryParam(String name, String value) {
|
||||
b.queryParam(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder setAttribute(String name, Object value) {
|
||||
attributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest build() {
|
||||
return new AuthRequest(id, b.build(), attributes);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
package org.keycloak.social;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -32,9 +33,27 @@ public class RequestDetails {
|
|||
|
||||
private Map<String, String> clientAttributes;
|
||||
|
||||
private Map<String, Object> socialAttributes;
|
||||
private Map<String, String> socialAttributes;
|
||||
|
||||
RequestDetails(String providerId, Map<String, String> clientAttributes, Map<String, Object> socialAttributes) {
|
||||
public static RequestDetailsBuilder create(String providerId) {
|
||||
RequestDetailsBuilder req = new RequestDetailsBuilder();
|
||||
req.providerId = providerId;
|
||||
req.clientAttributes = new HashMap<String, String>();
|
||||
req.socialAttributes = new HashMap<String, String>();
|
||||
return req;
|
||||
}
|
||||
|
||||
public static RequestDetailsBuilder create(RequestDetails from) {
|
||||
RequestDetailsBuilder req = new RequestDetailsBuilder();
|
||||
req.providerId = from.getProviderId();
|
||||
req.clientAttributes = new HashMap<String, String>();
|
||||
req.clientAttributes.putAll(from.getClientAttributes());
|
||||
req.socialAttributes = new HashMap<String, String>();
|
||||
req.socialAttributes.putAll(from.getSocialAttributes());
|
||||
return req;
|
||||
}
|
||||
|
||||
private RequestDetails(String providerId, Map<String, String> clientAttributes, Map<String, String> socialAttributes) {
|
||||
this.providerId = providerId;
|
||||
this.clientAttributes = clientAttributes;
|
||||
this.socialAttributes = socialAttributes;
|
||||
|
@ -52,12 +71,50 @@ public class RequestDetails {
|
|||
return clientAttributes;
|
||||
}
|
||||
|
||||
public Object getSocialAttribute(String name) {
|
||||
public String getSocialAttribute(String name) {
|
||||
return socialAttributes.get(name);
|
||||
}
|
||||
|
||||
public Map<String, Object> getSocialAttributes() {
|
||||
public Map<String, String> getSocialAttributes() {
|
||||
return socialAttributes;
|
||||
}
|
||||
|
||||
|
||||
public static class RequestDetailsBuilder {
|
||||
|
||||
private String providerId;
|
||||
|
||||
private Map<String, String> clientAttributes;
|
||||
|
||||
private Map<String, String> socialAttributes;
|
||||
|
||||
private RequestDetailsBuilder() {
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putClientAttribute(String name, String value) {
|
||||
clientAttributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putClientAttributes(Map<String, String> attributes) {
|
||||
clientAttributes.putAll(attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putSocialAttribute(String name, String value) {
|
||||
socialAttributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putSocialAttributes(Map<String, String> attributes) {
|
||||
socialAttributes.putAll(attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetails build() {
|
||||
return new RequestDetails(providerId, clientAttributes, socialAttributes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source.
|
||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
||||
* as indicated by the @author tags. See the copyright.txt file in the
|
||||
* distribution for a full listing of individual contributors.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
package org.keycloak.social;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class RequestDetailsBuilder {
|
||||
|
||||
private String providerId;
|
||||
|
||||
private Map<String, String> clientAttributes;
|
||||
|
||||
private Map<String, Object> socialAttributes;
|
||||
|
||||
private RequestDetailsBuilder() {
|
||||
}
|
||||
|
||||
public static RequestDetailsBuilder create(String providerId) {
|
||||
RequestDetailsBuilder req = new RequestDetailsBuilder();
|
||||
req.providerId = providerId;
|
||||
req.clientAttributes = new HashMap<String, String>();
|
||||
req.socialAttributes = new HashMap<String, Object>();
|
||||
return req;
|
||||
}
|
||||
|
||||
public static RequestDetailsBuilder createFromRequestDetails(RequestDetails from) {
|
||||
RequestDetailsBuilder req = new RequestDetailsBuilder();
|
||||
req.providerId = from.getProviderId();
|
||||
req.clientAttributes = new HashMap<String, String>();
|
||||
req.clientAttributes.putAll(from.getClientAttributes());
|
||||
req.socialAttributes = new HashMap<String, Object>();
|
||||
req.socialAttributes.putAll(from.getSocialAttributes());
|
||||
return req;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putClientAttribute(String name, String value) {
|
||||
clientAttributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putClientAttributes(Map<String, String> attributes) {
|
||||
clientAttributes.putAll(attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putSocialAttribute(String name, Object value) {
|
||||
socialAttributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetailsBuilder putSocialAttributes(Map<String, Object> attributes) {
|
||||
socialAttributes.putAll(attributes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RequestDetails build() {
|
||||
return new RequestDetails(providerId, clientAttributes, socialAttributes);
|
||||
}
|
||||
|
||||
}
|
|
@ -50,8 +50,4 @@ public class SocialProviderConfig {
|
|||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
|||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.AuthRequestBuilder;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
|
@ -45,13 +44,9 @@ public class FacebookProvider implements SocialProvider {
|
|||
public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
|
||||
String state = UUID.randomUUID().toString();
|
||||
|
||||
AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTHENTICATION_ENDPOINT_URL).setQueryParam("client_id", config.getKey())
|
||||
return AuthRequest.create(state, AUTHENTICATION_ENDPOINT_URL).setQueryParam("client_id", config.getKey())
|
||||
.setQueryParam("response_type", DEFAULT_RESPONSE_TYPE).setQueryParam("scope", DEFAULT_SCOPE)
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
|
||||
|
||||
b.setAttribute("state", state);
|
||||
|
||||
return b.build();
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
*/
|
||||
package org.keycloak.social.google;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
import org.keycloak.social.SocialUser;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
|
||||
|
@ -29,15 +38,6 @@ import com.google.api.client.json.jackson.JacksonFactory;
|
|||
import com.google.api.services.oauth2.Oauth2;
|
||||
import com.google.api.services.oauth2.model.Tokeninfo;
|
||||
import com.google.api.services.oauth2.model.Userinfo;
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.AuthRequestBuilder;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
import org.keycloak.social.SocialUser;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -62,14 +62,10 @@ public class GoogleProvider implements SocialProvider {
|
|||
@Override
|
||||
public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
|
||||
String state = UUID.randomUUID().toString();
|
||||
|
||||
AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTH_PATH).setQueryParam("client_id", config.getKey())
|
||||
|
||||
return AuthRequest.create(state, AUTH_PATH).setQueryParam("client_id", config.getKey())
|
||||
.setQueryParam("response_type", DEFAULT_RESPONSE_TYPE).setQueryParam("scope", DEFAULT_SCOPE)
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
|
||||
|
||||
b.setAttribute("state", state);
|
||||
|
||||
return b.build();
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,7 +23,6 @@ package org.keycloak.social.twitter;
|
|||
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.AuthRequestBuilder;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
|
@ -50,7 +49,7 @@ public class TwitterProvider implements SocialProvider {
|
|||
|
||||
RequestToken requestToken = twitter.getOAuthRequestToken(request.getCallbackUrl());
|
||||
|
||||
return AuthRequestBuilder.create(requestToken.getToken(), requestToken.getAuthenticationURL())
|
||||
return AuthRequest.create(requestToken.getToken(), requestToken.getAuthenticationURL())
|
||||
.setAttribute("token", requestToken.getToken()).setAttribute("tokenSecret", requestToken.getTokenSecret())
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -191,6 +191,10 @@
|
|||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-chrome-driver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
log4j.rootLogger=debug, stdout
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
|
||||
|
||||
log4j.logger.org.keycloak=debug
|
|
@ -2,7 +2,6 @@ package org.keycloak.testsuite;
|
|||
|
||||
import org.keycloak.social.AuthCallback;
|
||||
import org.keycloak.social.AuthRequest;
|
||||
import org.keycloak.social.AuthRequestBuilder;
|
||||
import org.keycloak.social.SocialProvider;
|
||||
import org.keycloak.social.SocialProviderConfig;
|
||||
import org.keycloak.social.SocialProviderException;
|
||||
|
@ -23,12 +22,8 @@ public class DummySocial implements SocialProvider {
|
|||
public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
|
||||
String state = UUID.randomUUID().toString();
|
||||
|
||||
AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTH_PATH).setQueryParam("response_type", "token")
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
|
||||
|
||||
b.setAttribute("state", state);
|
||||
|
||||
return b.build();
|
||||
return AuthRequest.create(state, AUTH_PATH).setQueryParam("response_type", "token")
|
||||
.setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,10 +30,14 @@ import org.apache.http.client.methods.HttpPost;
|
|||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.jboss.resteasy.jose.Base64Url;
|
||||
import org.jboss.resteasy.jwt.JsonSerialization;
|
||||
import org.jboss.resteasy.security.PemUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.VerificationException;
|
||||
import org.keycloak.representations.SkeletonKeyScope;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
@ -67,17 +71,21 @@ public class OAuthClient {
|
|||
|
||||
private String redirectUri = "http://localhost:8081/app/auth";
|
||||
|
||||
private String scope;
|
||||
private SkeletonKeyScope scope;
|
||||
|
||||
private String state;
|
||||
|
||||
private PublicKey realmPublicKey;
|
||||
|
||||
public OAuthClient(WebDriver driver) throws Exception {
|
||||
public OAuthClient(WebDriver driver) {
|
||||
this.driver = driver;
|
||||
|
||||
JSONObject realmJson = new JSONObject(IOUtils.toString(getClass().getResourceAsStream("/testrealm.json")));
|
||||
realmPublicKey = PemUtils.decodePublicKey(realmJson.getString("publicKey"));
|
||||
try {
|
||||
JSONObject realmJson = new JSONObject(IOUtils.toString(getClass().getResourceAsStream("/testrealm.json")));
|
||||
realmPublicKey = PemUtils.decodePublicKey(realmJson.getString("publicKey"));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to retrieve realm public key", e);
|
||||
}
|
||||
}
|
||||
|
||||
public AuthorizationCodeResponse doLogin(String username, String password) {
|
||||
|
@ -90,7 +98,15 @@ public class OAuthClient {
|
|||
return new AuthorizationCodeResponse(this);
|
||||
}
|
||||
|
||||
public AccessTokenResponse doAccessTokenRequest(String code, String password) throws Exception {
|
||||
public void doLoginGrant(String username, String password) {
|
||||
openLoginForm();
|
||||
|
||||
driver.findElement(By.id("username")).sendKeys(username);
|
||||
driver.findElement(By.id("password")).sendKeys(password);
|
||||
driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
|
||||
}
|
||||
|
||||
public AccessTokenResponse doAccessTokenRequest(String code, String password) {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpPost post = new HttpPost(getAccessTokenUrl());
|
||||
|
||||
|
@ -114,27 +130,19 @@ public class OAuthClient {
|
|||
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charset.forName("UTF-8"));
|
||||
post.setEntity(formEntity);
|
||||
|
||||
return new AccessTokenResponse(client.execute(post));
|
||||
try {
|
||||
return new AccessTokenResponse(client.execute(post));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to retrieve access token", e);
|
||||
}
|
||||
}
|
||||
|
||||
public SkeletonKeyToken verifyToken(String token) throws Exception {
|
||||
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
|
||||
}
|
||||
|
||||
public boolean isAuthorizationResponse() {
|
||||
return getCurrentRequest().equals(redirectUri) && getCurrentQuery().containsKey("code");
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getResponseType() {
|
||||
return responseType;
|
||||
public SkeletonKeyToken verifyToken(String token) {
|
||||
try {
|
||||
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
|
||||
} catch (VerificationException e) {
|
||||
throw new RuntimeException("Failed to verify token", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentRequest() {
|
||||
|
@ -174,10 +182,6 @@ public class OAuthClient {
|
|||
return redirectUri;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public String getLoginFormUrl() {
|
||||
UriBuilder b = UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/login");
|
||||
if (responseType != null) {
|
||||
|
@ -190,7 +194,12 @@ public class OAuthClient {
|
|||
b.queryParam("redirect_uri", redirectUri);
|
||||
}
|
||||
if (scope != null) {
|
||||
b.queryParam("scope", scope);
|
||||
try {
|
||||
|
||||
b.queryParam("scope", Base64Url.encode(JsonSerialization.toByteArray(scope, false)));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to serialize scope", e);
|
||||
}
|
||||
}
|
||||
if (state != null) {
|
||||
b.queryParam("state", state);
|
||||
|
@ -223,8 +232,11 @@ public class OAuthClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
public OAuthClient scope(String scope) {
|
||||
this.scope = scope;
|
||||
public OAuthClient addScope(String resource, String... roles) {
|
||||
if (scope == null) {
|
||||
scope = new SkeletonKeyScope();
|
||||
}
|
||||
scope.addAll(resource, roles);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source.
|
||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
||||
* as indicated by the @author tags. See the copyright.txt file in the
|
||||
* distribution for a full listing of individual contributors.
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this software; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
*/
|
||||
package org.keycloak.testsuite;
|
||||
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.keycloak.PemUtils;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.keycloak.servlet.ServletOAuthClient;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
|
||||
*/
|
||||
public class OAuthGrantServlet extends HttpServlet {
|
||||
|
||||
public static ServletOAuthClient client;
|
||||
|
||||
private static String baseUrl = Constants.AUTH_SERVER_ROOT + "/rest";
|
||||
private static String realm = "test";
|
||||
|
||||
private static String realmKeyPem = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvg" +
|
||||
"cwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/" +
|
||||
"p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
|
||||
|
||||
public void init() {
|
||||
client = new ServletOAuthClient();
|
||||
client.setClientId("third-party");
|
||||
client.setPassword("password");
|
||||
client.setAuthUrl(UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/login").build().toString());
|
||||
client.setCodeUrl(UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/access/codes").build().toString());
|
||||
client.setClient(new ResteasyClientBuilder().build());
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
|
||||
|
||||
PrintWriter pw = resp.getWriter();
|
||||
|
||||
// Error "access_denied" happens after clicking on cancel when asked for granting permission
|
||||
if (req.getParameterValues("error") != null){
|
||||
pw.print("<html><head><title></title></head><body>Access rights not granted.</body></html>");
|
||||
|
||||
// Code is sent as a parameter in case that access was granted
|
||||
} else if(req.getParameterValues("code") != null) {
|
||||
String token = client.getBearerToken(req);
|
||||
|
||||
pw.print("<html><head><title></title></head><body>Access rights granted.<br/>Token:"+token+"<br/>");
|
||||
|
||||
// Check whether the token itself is relevant
|
||||
try {
|
||||
PublicKey realmKey = PemUtils.decodePublicKey(realmKeyPem);
|
||||
SkeletonKeyToken skeletonToken = RSATokenVerifier.verifyToken(token, realmKey, realm);
|
||||
|
||||
// Writing app/role information on a page in format which is easy to assert in a test.
|
||||
pw.print("Role:");
|
||||
for(String role: skeletonToken.getRealmAccess().getRoles()){
|
||||
pw.print(role);
|
||||
}
|
||||
pw.print(".<br/>");
|
||||
|
||||
for(Map.Entry<String, SkeletonKeyToken.Access> entry: skeletonToken.getResourceAccess().entrySet()){
|
||||
pw.print("App:"+entry.getKey()+";");
|
||||
for(String role: entry.getValue().getRoles()){
|
||||
pw.print(role);
|
||||
}
|
||||
}
|
||||
pw.print(".<br/>");
|
||||
} catch (Exception e){
|
||||
}
|
||||
|
||||
pw.print("</body></html>");
|
||||
|
||||
// If no code was sent or error happened, it's 1st visit to servlet and we need to ask for permissions
|
||||
} else {
|
||||
client.redirectRelative("", req, resp);
|
||||
}
|
||||
|
||||
pw.flush();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
package org.keycloak.testsuite.account;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.Constants;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ProfileTest {
|
||||
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
UserModel user = appRealm.getUser("test-user@localhost");
|
||||
user.setFirstName("First");
|
||||
user.setLastName("Last");
|
||||
user.setAttribute("key1", "value1");
|
||||
user.setAttribute("key2", "value2");
|
||||
|
||||
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
||||
|
||||
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
||||
accountApp.addScopeMapping(app.getApplicationUser(), org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
||||
|
||||
app.getApplicationUser().addWebOrigin("http://localtest.me:8081");
|
||||
|
||||
UserModel thirdParty = appRealm.getUser("third-party");
|
||||
accountApp.addScopeMapping(thirdParty, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
||||
}
|
||||
});
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
||||
@WebResource
|
||||
protected WebDriver driver;
|
||||
|
||||
@WebResource
|
||||
protected OAuthClient oauth;
|
||||
|
||||
@WebResource
|
||||
protected AccountUpdateProfilePage profilePage;
|
||||
|
||||
@WebResource
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@WebResource
|
||||
protected OAuthGrantPage grantPage;
|
||||
|
||||
private List<String> defaultRoles;
|
||||
|
||||
@Test
|
||||
public void getProfile() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = oauth.getCurrentQuery().get("code");
|
||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
||||
|
||||
HttpResponse response = doGetProfile(token, null);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
JSONObject profile = new JSONObject(IOUtils.toString(response.getEntity().getContent()));
|
||||
|
||||
assertEquals("test-user@localhost", profile.getString("username"));
|
||||
assertEquals("test-user@localhost", profile.getString("email"));
|
||||
assertEquals("First", profile.getString("firstName"));
|
||||
assertEquals("Last", profile.getString("lastName"));
|
||||
|
||||
JSONObject attributes = profile.getJSONObject("attributes");
|
||||
assertEquals(2, attributes.length());
|
||||
assertEquals("value1", attributes.getString("key1"));
|
||||
assertEquals("value2", attributes.getString("key2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileCors() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = oauth.getCurrentQuery().get("code");
|
||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
||||
|
||||
driver.navigate().to("http://localtest.me:8081/app");
|
||||
|
||||
String[] response = doGetProfileJs(token);
|
||||
assertEquals("200", response[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileCorsInvalidOrigin() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = oauth.getCurrentQuery().get("code");
|
||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
||||
|
||||
driver.navigate().to("http://invalid.localtest.me:8081");
|
||||
|
||||
try {
|
||||
doGetProfileJs(token);
|
||||
fail("Expected failure");
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileCookieAuth() throws Exception {
|
||||
profilePage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
String[] response = doGetProfileJs(null);
|
||||
assertEquals("200", response[0]);
|
||||
|
||||
JSONObject profile = new JSONObject(response[1]);
|
||||
assertEquals("test-user@localhost", profile.getString("username"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileNoAuth() throws Exception {
|
||||
HttpResponse response = doGetProfile(null, null);
|
||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileNoAccess() throws Exception {
|
||||
try {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ApplicationModel app = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
||||
defaultRoles = app.getDefaultRoles();
|
||||
app.updateDefaultRoles(new String[0]);
|
||||
}
|
||||
});
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = oauth.getCurrentQuery().get("code");
|
||||
String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
|
||||
|
||||
HttpResponse response = doGetProfile(token, null);
|
||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray(new String[0]));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileOAuthClient() throws Exception {
|
||||
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
grantPage.accept();
|
||||
|
||||
String token = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password").getAccessToken();
|
||||
HttpResponse response = doGetProfile(token, null);
|
||||
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
JSONObject profile = new JSONObject(IOUtils.toString(response.getEntity().getContent()));
|
||||
|
||||
assertEquals("test-user@localhost", profile.getString("username"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProfileOAuthClientNoScope() throws Exception {
|
||||
oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
String token = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password").getAccessToken();
|
||||
HttpResponse response = doGetProfile(token, null);
|
||||
|
||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
private URI getAccountURI() {
|
||||
return UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT + "/rest/realms/" + oauth.getRealm() + "/account").build();
|
||||
}
|
||||
|
||||
private HttpResponse doGetProfile(String token, String origin) throws IOException {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpGet get = new HttpGet(UriBuilder.fromUri(getAccountURI()).build());
|
||||
if (token != null) {
|
||||
get.setHeader(HttpHeaders.AUTHORIZATION, "bearer " + token);
|
||||
}
|
||||
if (origin != null) {
|
||||
get.setHeader("Origin", origin);
|
||||
}
|
||||
get.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
return client.execute(get);
|
||||
}
|
||||
|
||||
private String[] doGetProfileJs(String token) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("var req = new XMLHttpRequest();\n");
|
||||
sb.append("req.open('GET', '" + getAccountURI().toString() + "', false);\n");
|
||||
if (token != null) {
|
||||
sb.append("req.setRequestHeader('Authorization', 'Bearer " + token + "');\n");
|
||||
}
|
||||
sb.append("req.setRequestHeader('Accept', 'application/json');\n");
|
||||
sb.append("req.send(null);\n");
|
||||
sb.append("return req.status + '///' + req.responseText;\n");
|
||||
|
||||
JavascriptExecutor js = (JavascriptExecutor) driver;
|
||||
String response = (String) js.executeScript(sb.toString());
|
||||
return response.split("///");
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ public class RequiredActionMultipleActionsTest {
|
|||
protected LoginUpdateProfilePage updateProfilePage;
|
||||
|
||||
@Test
|
||||
public void updateProfileAndPassword() {
|
||||
public void updateProfileAndPassword() throws Exception {
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ public class RequiredActionResetPasswordTest {
|
|||
protected LoginPasswordUpdatePage changePasswordPage;
|
||||
|
||||
@Test
|
||||
public void tempPassword() {
|
||||
public void tempPassword() throws Exception {
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
|
|
|
@ -21,29 +21,26 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.forms;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.junit.*;
|
||||
import org.keycloak.models.*;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||
import org.keycloak.testsuite.pages.AccountTotpPage;
|
||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.*;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -77,8 +74,13 @@ public class AccountTest {
|
|||
@WebResource
|
||||
protected AccountTotpPage totpPage;
|
||||
|
||||
@WebResource
|
||||
protected ErrorPage errorPage;
|
||||
|
||||
private TimeBasedOTP totp = new TimeBasedOTP();
|
||||
|
||||
private List<String> defaultRoles;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
keycloakRule.configure(new KeycloakSetup() {
|
||||
|
@ -185,4 +187,31 @@ public class AccountTest {
|
|||
Assert.assertTrue(driver.getPageSource().contains("Remove Google"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeProfileNoAccess() throws Exception {
|
||||
try {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ApplicationModel app = appRealm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
|
||||
defaultRoles = app.getDefaultRoles();
|
||||
app.updateDefaultRoles(new String[0]);
|
||||
}
|
||||
});
|
||||
|
||||
profilePage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
Assert.assertTrue(errorPage.isCurrent());
|
||||
Assert.assertEquals("No access", errorPage.getError());
|
||||
} finally {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray(new String[0]));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ public class LoginTotpTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void loginWithTotpFailure() {
|
||||
public void loginWithTotpFailure() throws Exception {
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
|
@ -106,7 +106,7 @@ public class LoginTotpTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void loginWithTotpSuccess() {
|
||||
public void loginWithTotpSuccess() throws Exception {
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
||||
|
|
|
@ -21,13 +21,16 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.oauth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.SkeletonKeyToken;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthGrantServlet;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
|
@ -35,8 +38,6 @@ import org.keycloak.testsuite.rule.WebResource;
|
|||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
|
||||
*/
|
||||
|
@ -45,11 +46,6 @@ public class OAuthGrantTest {
|
|||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule();
|
||||
|
||||
@BeforeClass
|
||||
public static void before() {
|
||||
keycloakRule.deployServlet("grant", "/grant", OAuthGrantServlet.class);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
||||
|
@ -65,28 +61,13 @@ public class OAuthGrantTest {
|
|||
@WebResource
|
||||
protected OAuthGrantPage grantPage;
|
||||
|
||||
private static String GRANT_APP_URL = "http://localhost:8081/grant/";
|
||||
|
||||
private static String ACCESS_GRANTED = "Access rights granted.";
|
||||
private static String ACCESS_NOT_GRANTED = "Access rights not granted.";
|
||||
|
||||
private static String ROLE_USER = "Have User privileges";
|
||||
private static String ROLE_CUSTOMER = "Have Customer User privileges";
|
||||
|
||||
private static String GRANT_ROLE = "user";
|
||||
private static String GRANT_APP = "test-app";
|
||||
private static String GRANT_APP_ROLE = "customer-user";
|
||||
|
||||
@Test
|
||||
public void oauthGrantAcceptTest() throws IOException {
|
||||
|
||||
driver.navigate().to(GRANT_APP_URL);
|
||||
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
|
||||
|
||||
loginPage.isCurrent();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
grantPage.assertCurrent();
|
||||
Assert.assertTrue(driver.getPageSource().contains(ROLE_USER));
|
||||
|
@ -94,23 +75,50 @@ public class OAuthGrantTest {
|
|||
|
||||
grantPage.accept();
|
||||
|
||||
Assert.assertTrue(driver.getPageSource().contains(ACCESS_GRANTED));
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
|
||||
Assert.assertTrue(oauth.getCurrentQuery().containsKey("code"));
|
||||
OAuthClient.AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
|
||||
|
||||
Assert.assertTrue(driver.getPageSource().contains("Role:"+ GRANT_ROLE +"."));
|
||||
Assert.assertTrue(driver.getPageSource().contains("App:"+ GRANT_APP +";"+ GRANT_APP_ROLE +"."));
|
||||
SkeletonKeyToken token = oauth.verifyToken(accessToken.getAccessToken());
|
||||
|
||||
SkeletonKeyToken.Access realmAccess = token.getRealmAccess();
|
||||
Assert.assertEquals(1, realmAccess.getRoles().size());
|
||||
Assert.assertTrue(realmAccess.isUserInRole("user"));
|
||||
|
||||
Map<String,SkeletonKeyToken.Access> resourceAccess = token.getResourceAccess();
|
||||
Assert.assertEquals(1, resourceAccess.size());
|
||||
Assert.assertEquals(1, resourceAccess.get("test-app").getRoles().size());
|
||||
Assert.assertTrue(resourceAccess.get("test-app").isUserInRole("customer-user"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oauthGrantAcceptTestWithScope() throws IOException {
|
||||
oauth.addScope("test-app", "customer-user");
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
grantPage.assertCurrent();
|
||||
Assert.assertTrue(driver.getPageSource().contains(ROLE_CUSTOMER));
|
||||
|
||||
grantPage.accept();
|
||||
|
||||
Assert.assertTrue(oauth.getCurrentQuery().containsKey("code"));
|
||||
OAuthClient.AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
|
||||
|
||||
SkeletonKeyToken token = oauth.verifyToken(accessToken.getAccessToken());
|
||||
|
||||
SkeletonKeyToken.Access realmAccess = token.getRealmAccess();
|
||||
Assert.assertNull(realmAccess);
|
||||
|
||||
Map<String,SkeletonKeyToken.Access> resourceAccess = token.getResourceAccess();
|
||||
Assert.assertEquals(1, resourceAccess.size());
|
||||
Assert.assertEquals(1, resourceAccess.get("test-app").getRoles().size());
|
||||
Assert.assertTrue(resourceAccess.get("test-app").isUserInRole("customer-user"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oauthGrantCancelTest() throws IOException {
|
||||
|
||||
driver.navigate().to(GRANT_APP_URL);
|
||||
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
|
||||
|
||||
loginPage.isCurrent();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
grantPage.assertCurrent();
|
||||
Assert.assertTrue(driver.getPageSource().contains(ROLE_USER));
|
||||
|
@ -118,7 +126,7 @@ public class OAuthGrantTest {
|
|||
|
||||
grantPage.cancel();
|
||||
|
||||
Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
|
||||
Assert.assertTrue(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
|
||||
Assert.assertTrue(oauth.getCurrentQuery().containsKey("error"));
|
||||
Assert.assertEquals("access_denied", oauth.getCurrentQuery().get("error"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,6 @@ public abstract class AbstractPage {
|
|||
|
||||
abstract boolean isCurrent();
|
||||
|
||||
abstract void open();
|
||||
abstract void open() throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ public class WebRule extends ExternalResource {
|
|||
|
||||
if (browser.equals("htmlunit")) {
|
||||
HtmlUnitDriver d = new HtmlUnitDriver();
|
||||
d.getWebClient().getOptions().setJavaScriptEnabled(true);
|
||||
d.getWebClient().getOptions().setCssEnabled(false);
|
||||
driver = d;
|
||||
} else if (browser.equals("chrome")) {
|
||||
|
|
|
@ -78,13 +78,6 @@ public class CreateUsersWorker implements Worker {
|
|||
user.setEmail(username + "@email.com");
|
||||
}
|
||||
|
||||
// Adding default roles of realm to user
|
||||
if (addDefaultRoles) {
|
||||
for (RoleModel role : realm.getDefaultRoles()) {
|
||||
realm.grantRole(user, role);
|
||||
}
|
||||
}
|
||||
|
||||
// Creating password (will be same as username)
|
||||
if (addPassword) {
|
||||
UserCredentialModel password = new UserCredentialModel();
|
||||
|
|