+ <#if realm.internationalizationEnabled>
+
+
+ <#list realm.supportedLocales as l>
+ selected="selected"#if>>${rb["locale_" + l]}
+ #list>
+
+
+ #if>
<#if referrer?has_content && referrer.url?has_content> Back to ${referrer.name} #if>
Sign Out
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/index.ftl b/forms/common-themes/src/main/resources/theme/admin/base/index.ftl
index e4a8a19ea4..161acdad73 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/index.ftl
+++ b/forms/common-themes/src/main/resources/theme/admin/base/index.ftl
@@ -26,7 +26,7 @@
-
+
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index e132cb4a9b..3873df1193 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -403,6 +403,18 @@ module.controller('RealmLoginSettingsCtrl', function($scope, Current, Realm, rea
module.controller('RealmThemeCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications) {
genericRealmUpdate($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications, "/realms/" + realm.realm + "/theme-settings");
+
+ $scope.supportedLocalesOptions = {
+ 'multiple' : true,
+ 'simple_tags' : true,
+ 'tags' : ['en', 'de']
+ };
+
+ $scope.$watch('realm.supportedLocales', function(oldVal, newVal) {
+ if(angular.isUndefined(newVal) || (angular.isArray(newVal) && newVal.length == 0)){
+ $scope.realm.defaultLocale = undefined;
+ }
+ }, true);
});
module.controller('RealmCacheCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications) {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
index b3b0edfcee..53bcf1f1fa 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
@@ -1042,7 +1042,8 @@ module.factory('PasswordPolicy', function() {
digits: "Minimal number (integer type) of digits in password. Default value is 1.",
lowerCase: "Minimal number (integer type) of lowercase characters in password. Default value is 1.",
upperCase: "Minimal number (integer type) of uppercase characters in password. Default value is 1.",
- specialChars: "Minimal number (integer type) of special characters in password. Default value is 1."
+ specialChars: "Minimal number (integer type) of special characters in password. Default value is 1.",
+ notUsername: "Block passwords that are equal to the username"
}
p.allPolicies = [
@@ -1051,7 +1052,8 @@ module.factory('PasswordPolicy', function() {
{ name: 'digits', value: 1 },
{ name: 'lowerCase', value: 1 },
{ name: 'upperCase', value: 1 },
- { name: 'specialChars', value: 1 }
+ { name: 'specialChars', value: 1 },
+ { name: 'notUsername', value: 1 }
];
p.parse = function(policyString) {
@@ -1068,9 +1070,9 @@ module.factory('PasswordPolicy', function() {
var re = /(\w+)\(*(\d*)\)*/;
var policyEntry = re.exec(policyToken);
-
- policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
-
+ if (null !== policyEntry) {
+ policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
+ }
}
return policies;
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-credentials.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-credentials.html
index 6dff85cba7..608a2b622f 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-credentials.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-credentials.html
@@ -46,7 +46,9 @@
-
+
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
index c08d5f9d43..5d5a927de6 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-theme-settings.html
@@ -59,6 +59,33 @@
+
+
+
+
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
index 38d150fd5d..301212fff9 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/email-verification.ftl
@@ -1,5 +1 @@
-Someone has created a Keycloak account with this email address. If this was you, click the link below to verify your email address:
-${link}
-This link will expire within ${linkExpiration} minutes.
-
-If you didn't create this account, just ignore this message.
\ No newline at end of file
+${formatter.format(rb.emailVerificationBody,link, linkExpiration)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
index c1227aa882..cd9d247d9d 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-login_error.ftl
@@ -1 +1 @@
-A failed login attempt was dettected to your account on ${event.date?datetime} from ${event.ipAddress}. If this was not you, please contact an admin.
\ No newline at end of file
+${formatter.format(rb.eventLoginErrorBody,event.date,event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
index c62e174053..37ae2f73a3 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-remove_totp.ftl
@@ -1 +1 @@
-TOTP was removed from your account on ${event.date?datetime} from ${event.ipAddress}. If this was not you, please contact an admin.
\ No newline at end of file
+${formatter.format(rb.eventRemoveTotpBody,event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
index 696a6e6181..2c88214097 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_password.ftl
@@ -1 +1 @@
-Your password was changed on ${event.date?datetime} from ${event.ipAddress}. If this was not you, please contact an admin.
\ No newline at end of file
+${formatter.format(rb.eventUpdatePasswordBody,event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
index 531ae662be..b34a898086 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/event-update_totp.ftl
@@ -1 +1 @@
-TOTP was updated for your account on ${event.date?datetime} from ${event.ipAddress}. If this was not you, please contact an admin.
\ No newline at end of file
+${formatter.format(rb.eventUpdateTotpBody,event.date, event.ipAddress)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages.properties b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages.properties
deleted file mode 100755
index 3139aca340..0000000000
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-emailVerificationSubject=Verify email
-passwordResetSubject=Reset password
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_de.properties
new file mode 100644
index 0000000000..a5a85f9ecf
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_de.properties
@@ -0,0 +1,12 @@
+emailVerificationSubject=E-Mail verifizieren
+passwordResetSubject=Passwort zurückzusetzen
+passwordResetBody=Jemand hat angeforder Ihr Keycloak Passwort zurückzusetzen. Falls das Sie waren, dann klicken Sie auf den folgenden Link um das Passwort zurückzusetzen.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie das Passwort nicht zurücksetzen möchten, dann können Sie diese E-Mail ignorieren.
+emailVerificationBody=Jemand hat ein Keycloak Konto mit dieser E-Mail Adresse erstellt. Fall das Sie waren, dann klicken Sie auf den Link um die E-Mail Adresse zu verifizieren.\n\n{0}\n\nDieser Link wird in {1} Minuten ablaufen.\n\nFalls Sie dieses Konto nicht erstellt haben, dann können sie diese Nachricht ignorieren.
+eventLoginErrorSubject=Fehlgeschlagene Anmeldung
+eventLoginErrorBody=Jemand hat um {0} von {1} versucht sich mit ihrem Konto anzumelden. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventRemoveTotpSubject=TOTP Entfernt
+eventRemoveTotpBody=TOTP wurde von ihrem Konto am {0} von {1} entfernt. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventUpdatePasswordSubject=Passwort Aktualisiert
+eventUpdatePasswordBody=Ihr Passwort wurde am {0} von {1} geändert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
+eventUpdateTotpSubject=TOTP Aktualisiert
+eventUpdateTotpBody=TOTP wurde am {0} von {1} geändert. Falls das nicht Sie waren, dann kontaktieren Sie bitte Ihren Admin.
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties
new file mode 100755
index 0000000000..e64a00fb68
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/messages/messages_en.properties
@@ -0,0 +1,12 @@
+emailVerificationSubject=Verify email
+emailVerificationBody=Someone has created a Keycloak account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you didn't create this account, just ignore this message.
+passwordResetSubject=Reset password
+passwordResetBody=Someone just requested to change your Keycloak account's password. If this was you, click on the link below to set a new password\n\n{0}\n\nThis link will expire within {1} minutes.\n\nIf you don't want to reset your password, just ignore this message and nothing will be changed.
+eventLoginErrorSubject=Login error
+eventLoginErrorBody=A failed login attempt was dettected to your account on {0} from {1}. If this was not you, please contact an admin.
+eventRemoveTotpSubject=Remove TOTP
+eventRemoveTotpBody=TOTP was removed from your account on {0} from {1}. If this was not you, please contact an admin.
+eventUpdatePasswordSubject=Update password
+eventUpdatePasswordBody=Your password was changed on {0} from {1}. If this was not you, please contact an admin.
+eventUpdateTotpSubject=Update TOTP
+eventUpdateTotpBody=TOTP was updated for your account on {0} from {1}. If this was not you, please contact an admin.
diff --git a/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl b/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
index 5d277e5e2b..55f0138bef 100644
--- a/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
+++ b/forms/common-themes/src/main/resources/theme/email/keycloak/password-reset.ftl
@@ -1,5 +1 @@
-Someone just requested to change your Keycloak account's password. If this was you, click on the link below to set a new password:
-${link}
-This link will expire within ${linkExpiration} minutes.
-
-If you don't want to reset your password, just ignore this message and nothing will be changed.
\ No newline at end of file
+${formatter.format(rb.passwordResetBody,link, linkExpiration)}
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
index d71536c965..c884ad4b75 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-config-totp.ftl
@@ -23,7 +23,7 @@
-
+
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
index c881e9c9be..797b62d7ce 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-oauth-grant.ftl
@@ -4,7 +4,7 @@
<#if section = "title">
${rb.oauthGrantTitle}
<#elseif section = "header">
- Temporary access for ${(realm.name)!''} requested by ${(client.clientId)!''} .
+ ${formatter.format(rb.oauthGrantTitleHtml,(realm.name!''), (client.clientId!''))}
<#elseif section = "form">
${rb.oauthGrantRequest}
@@ -55,8 +55,8 @@
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
index aca7d76ac8..9fe7a15ac8 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-reset-password.ftl
@@ -1,9 +1,9 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout displayInfo=true; section>
<#if section = "title">
- ${rb.emailForgotHeader}
+ ${rb.emailForgotTitle}
<#elseif section = "header">
- ${rb.emailForgotHeader}
+ ${rb.emailForgotTitle}
<#elseif section = "form">
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
index 613e8f2593..8661fa0fa5 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-totp.ftl
@@ -1,9 +1,9 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "title">
- ${rb.loginTitle} ${realm.name}
+ ${formatter.format(rb.loginTitle,realm.name)}
<#elseif section = "header">
- ${rb.loginTitle} ${realm.name}
+ ${formatter.format(rb.loginTitleHtml,realm.name)}
<#elseif section = "form">
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
index 812e29eb70..c3e1d9b303 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-update-profile.ftl
@@ -40,7 +40,7 @@
-
+
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl b/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
index 19e9bee15b..ac48f95c99 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login-verify-email.ftl
@@ -6,10 +6,10 @@
${rb.emailVerifyTitle}
<#elseif section = "form">
- ${rb.emailVerifyInstr}
+ ${rb.emailVerifyInstruction1}
- ${rb.emailVerifyInstrQ}
- ${rb.emailVerifyClick} ${rb.emailVerifyResend}
+
+ ${rb.emailVerifyInstruction2} ${rb.doClickHere} ${rb.emailVerifyInstruction3}
#if>
@layout.registrationLayout>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login.ftl b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
index e46cf9518d..e514b9ee6c 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
@@ -2,15 +2,15 @@
<@layout.registrationLayout displayInfo=social.displayInfo; section>
<#if section = "title">
<#if client.application>
- ${rb.loginTitle} ${realm.name}
+ ${formatter.format(rb.loginTitle,(realm.name!''))}
<#elseif client.oauthClient>
- ${realm.name} ${rb.loginOauthTitle}
+ ${formatter.format(rb.loginOauthTitle,(realm.name!''))}
#if>
<#elseif section = "header">
<#if client.application>
- ${rb.loginTitle} ${(realm.name)!''}
+ ${formatter.format(rb.loginTitleHtml,(realm.name!''))}
<#elseif client.oauthClient>
- Temporary access for ${(realm.name)!''} requested by ${(client.clientId)!''} .
+ ${formatter.format(rb.loginOauthTitleHtml,(realm.name!''), (client.clientId!''))}
#if>
<#elseif section = "form">
<#if realm.password>
@@ -41,24 +41,24 @@
<#if login.rememberMe??>
- Remember Me
+ ${rb.rememberMe}
<#else>
- Remember Me
+ ${rb.rememberMe}
#if>
#if>
@@ -75,7 +75,7 @@
<#elseif section = "info" >
<#if realm.password && realm.registrationAllowed>
#if>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties
deleted file mode 100755
index 0a59a69c69..0000000000
--- a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties
+++ /dev/null
@@ -1,126 +0,0 @@
-logIn=Log in
-logInTo=Log in to
-logInWith=Log in with
-noAccount=New user?
-register=Register
-registerWith=Register with
-allRequired=All fields are required
-alreadyHaveAccount=Already have an account?
-street=Street
-locality=City or Locality
-region=State, Province, or Region
-postal_code=Zip or Postal code
-country=Country
-
-poweredByKeycloak=Powered by Keycloak
-
-username=Username
-usernameOrEmail=Username or email
-fullName=Full name
-firstName=First name
-lastName=Last name
-email=Email
-password=Password
-rememberMe=Remember me
-passwordConfirm=Confirm password
-passwordNew=New Password
-passwordNewConfirm=New Password confirmation
-passwordUpdated=Password updated
-cancel=Cancel
-accept=Accept
-submit=Submit
-yes=Yes
-no=No
-
-authenticatorCode=One-time code
-clientCertificate=Client Certificate
-
-invalidUser=Invalid username or password.
-invalidPassword=Invalid username or password.
-invalidEmail=Invalid email address
-accountDisabled=Account is disabled, contact admin
-accountTemporarilyDisabled=Account is temporarily disabled, contact admin or try again later
-expiredCode=Login timeout. Please login again
-
-missingFirstName=Please specify first name
-missingLastName=Please specify last name
-missingEmail=Please specify email
-missingUsername=Please specify username
-missingPassword=Please specify password.
-notMatchPassword=Passwords don't match
-missingTotp=Please specify authenticator code
-
-invalidPasswordExisting=Invalid existing password
-invalidPasswordConfirm=Password confirmation doesn't match
-invalidTotp=Invalid authenticator code
-
-successTotp=Mobile authenticator configured.
-successTotpRemoved=Mobile authenticator removed.
-
-usernameExists=Username already exists
-emailExists=Email already exists
-
-federatedIdentityEmailExists=User with email already exists. Please login to account management to link the account.
-federatedIdentityUsernameExists=User with username already exists. Please login to account management to link the account.
-federatedIdentityRegistrationEmailMissing=Email is not provided. Use another provider to create account please.
-
-loginTitle=Log in to
-loginOauthTitle=Temporary access.
-loginOauthTitleHtml=Temporary access requested. Login to grant access.
-loginForgot=Forgot
-
-loginTotpTitle=Mobile Authenticator Setup
-loginTotpStep1=Install FreeOTP or Google Authenticator on your mobile
-loginTotpStep2=Open the application and scan the barcode or enter the key
-loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup
-loginTotpOneTime=One-time code
-
-loginProfileTitle=Update Account Information
-loginProfileWarning=Your account is not enabled because you need to update your account information.
-loginProfileWarningFollow=Please follow the steps below.
-loginProfileError=Some required fields are empty or incorrect.
-loginProfileErrorSteps=Please correct the fields in red.
-
-oauthGrantTitle=OAuth Grant
-oauthGrantTitleHtml=Temporary access requested
-oauthGrantTerms=Keycloak Central Login and Google will use this information in accordance with their respective terms of service and privacy policies.
-oauthGrantRequest=Do you grant these access privileges?
-oauthGrantLoginRequest=Do you grant access?
-
-emailVerifyTitle=Email verification
-emailVerifyInstr=An email with instructions to verify your email address has been sent to you.
-emailVerifyInstrQ=Haven't received a verification code in your email?
-emailVerifyClick=Click here
-emailVerifyResend=to re-send the email.
-emailVerified=Email verified
-
-error=A system error has occured, contact admin
-errorTitle=We're sorry...
-errorTitleHtml=We're sorry ...
-errorGenericMsg=Something happened and we could not process your request.
-actionWarningHeader=Your account is not enabled.
-actionTotpWarning=You need to set up Mobile Authenticator to activate your account.
-actionProfileWarning=You need to update your user profile to activate your account.
-actionPasswordWarning=You need to change your password to activate your account.
-actionEmailWarning=You need to verify your email address to activate your account.
-actionFollow=Please fill in the fields below.
-
-errorKerberosLogin=Kerberos ticket not available. Authenticate with password.
-
-successHeader=Success!
-errorHeader=Error!
-
-# Forgot password part
-
-emailForgotHeader=Forgot Your Password?
-backToLogin=« Back to Login
-backToApplication=« Back to Application
-emailUpdateHeader=Update password
-emailSent=You should receive an email shortly with further instructions.
-emailSendError=Failed to send email, please try again later
-emailError=Invalid email.
-emailErrorInfo=Please, fill in the fields again.
-emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
-
-accountUpdated=Your account has been updated
-accountPasswordUpdated=Your password has been updated
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties
new file mode 100644
index 0000000000..70d8aba28c
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_de.properties
@@ -0,0 +1,148 @@
+doLogIn=Anmelden
+doRegister=Registrieren
+doCancel=Abbrechen
+doSubmit=Absenden
+doYes=Ja
+doNo=Nein
+doForgotPassword=Passwort vergessen?
+doClickHere=hier klicken
+
+registerWithTitle=Registrierung bei {0}
+registerWithTitleHtml=Registrierung bei {0}
+loginTitle=Anmeldung bei {0}
+loginTitleHtml=Anmeldung bei {0}
+loginOauthTitle=Temporärer zugriff auf {0}
+loginOauthTitleHtml=Temporärer zugriff auf {0} angefordert von {1} .
+loginTotpTitle=Mobile Authentifizierung Einrichten
+loginProfileTitle=Benutzer Konto Informatinen aktualisieren
+oauthGrantTitle=OAuth gewähren
+oauthGrantTitleHtml=Temporärer zugriff auf {0} angefordert von {1} .
+errorTitle=Es tut uns leid...
+errorTitleHtml=Es tut uns leid...
+emailVerifyTitle=E-Mail verifizieren
+emailForgotTitle=Passwort vergessen?
+updatePasswordTitle=Passwort aktualisieren
+
+noAccount=Neuer Benutzer?
+username=Benutzername
+usernameOrEmail=Benutzername oder E-Mail
+firstName=Vorname
+fullName=Name
+lastName=Nachname
+email=E-Mail
+password=Passwort
+passwordConfirm=Passwort bestätigen
+passwordNew=Neues Passwort
+passwordNewConfirm=Neues Passwort bestätigen
+rememberMe=Angemeldet bleiben
+authenticatorCode=One-time Code
+street=Strasse
+region=Staat, Provinz, Region
+postal_code=PLZ
+locality=Stadt oder Ortschaft
+country=Land
+
+loginTotpStep1=Installieren Sie FreeOTP oder Google Authenticator auf Ihrem Smartphone.
+loginTotpStep2=Öffnen Sie die Applikation und scannen Sie den Barcode oder geben sie den Code ein.
+loginTotpStep3=Geben Sie den One-time Code welcher die Applikation generiert hat ein und klicken Sie auf Absenden.
+loginTotpOneTime=One-time Code
+
+oauthGrantRequest=Do you grant these access privileges?
+
+emailVerifyInstruction1=Ein E-Mail mit weitern Anweisungen wurde an Sie versendet.
+emailVerifyInstruction2=Falls Sie kein E-Mail erhalten haben, dann können Sie
+emailVerifyInstruction3=um ein neues E-Mail zu verschicken.
+
+backToLogin=« Zurück zur Anmeldung
+backToApplication=« Zurück zur Applikation
+
+emailInstruction=Geben Sie ihren Benutzernamen oder E-Mail Adresse ein und klicken Sie auf Absenden. Danach werden wir ihnen ein E-Mail mit weiteren Instruktionen zusenden.
+
+invalidUserMessage=Ungültiger Benutzername oder Passwort.
+invalidEmailMessage=Ungültige E-Mail Adresse.
+accountDisabledMessage=Benutzerkonto ist gesperrt, bitte kontaktieren Sie den Admin.
+accountTemporarilyDisabledMessage=Benutzerkonto ist temporär gespert, bitte kontaktieren Sie den Admin oder versuchen Sie es später nocheinmal.
+expiredCodeMessage=Zeitüberschreitung bei der Anmeldung. Bitter melden Sie sich erneut an.
+
+missingFirstNameMessage=Bitte geben Sie einen Vornamen ein.
+missingLastNameMessage=Bitte geben Sie einen Nachnamen ein.
+missingEmailMessage=Bitte geben Sie eine E-Mail Adresse ein.
+missingUsernameMessage=Bitte geben Sie einen Benutzernamen ein.
+missingPasswordMessage=Bitte geben Sie ein Passwort ein.
+missingTotpMessage=Bitte geben Sie den One-time Code ein.
+notMatchPasswordMessage=Passwörter sind nicht identisch.
+
+invalidPasswordExistingMessage=Das aktuelle Passwort is ungültig.
+invalidPasswordConfirmMessage=Die Passwort bestätigung ist nicht identisch.
+invalidTotpMessage=Ungültiger One-time Code.
+
+usernameExistsMessage=Benutzermane exisitert bereits.
+emailExistsMessage=E-Mail existiert bereits.
+
+federatedIdentityRegistrationEmailMissingMessage=Die E-Mail Adresse ist nicht vorhanden. Bitte verwenden Sie einen anderen Provider um das Benutzerkonto zu erstellen.
+federatedIdentityEmailExistsMessage=Es exisitert bereits ein Benutzer mit dieser E-Mail Adresse. Bitte melden Sie sich bei der Benutzerverwaltung an um das Benutzerkonto zu verknüpfen.
+federatedIdentityUsernameExistsMessage=Es exisitert bereits ein Benutzer mit diesem Benutzernamen. Bitte melden Sie sich bei der Benutzerverwaltung an um das Benutzerkonto zu verknüpfen.
+
+configureTotpMessage=Sie müssen eine Mobile Authentifizierung einrichten um das Benutzerkonto zu aktivieren.
+updateProfileMessage=Sie müssen ihr Benutzerkonto aktualisieren um das Benutzerkonto zu aktivieren.
+updatePasswordMessage=Sie müssen ihr Passwort ändern um das Benutzerkonto zu aktivieren.
+verifyEmailMessage=Sie müssen ihre E-Mail Adresse verifizieren um das Benutzerkonto zu aktivieren.
+
+emailSentMessage=Sie sollten in kürze ein E-Mail mit weiteren Instruktionen erhalten.
+emailSendErrorMessage=Das E-Mail konnte nicht versendet werden, bitte versuchen Sie es später nochmals.
+
+accountUpdatedMessage=Ihr Benutzerkonto wurde aktualisiert.
+accountPasswordUpdatedMessage=Ihr Passwort wurde aktualisiert.
+
+noAccessMessage=Kein Zugriff
+
+invalidPasswordMinLengthMessage=Ungültiges Passwort: minimum länge {0}.
+invalidPasswordMinDigitsMessage=Ungültiges Passwort: muss mindestens {0} Zahl(en) beinhalten.
+invalidPasswordMinLowerCaseCharsMessage=Ungültiges Passwort: muss mindestens {0} Kleinbuchstaben beinhalten.
+invalidPasswordMinUpperCaseCharsMessage=Ungültiges Passwort: muss mindestens {0} Grossbuchstaben beinhalten.
+invalidPasswordMinSpecialCharsMessage=Ungültiges Passwort: muss mindestens {0} Spezialzeichen beinhalten.
+invalidPasswordNotUsernameMessage=Ungültiges Passwort\: darf nicht gleich sein wie Benutzername.
+
+failedToProcessResponseMessage=Konnte Response nicht verarbeiten.
+httpsRequiredMessage=HTTPS erforderlich.
+realmNotEnabledMessage=Realm nicht aktiviert.
+invalidRequestMessage=Ungültiger Request.
+unknownLoginRequesterMessage=Ungültiger login requester
+loginRequesterNotEnabledMessage=Login requester nicht aktiviert.
+bearerOnlyMessage=Bearer-only Applikationen könne sich nicht via Browser anmelden.
+directGrantsOnlyMessage=Direct-grants-only Clients könne sich nicht via Browser anmelden.
+invalidRedirectUriMessage=Ungültige redirect uri.
+unsupportedNameIdFormatMessage=Nicht unterstütztes NameIDFormat.
+invlidRequesterMessage=Ungültiger requester.
+registrationNotAllowedMessage=Registrierung nicht erlaubt.
+
+permissionNotApprovedMessage=Berechtigung nicht bestätigt.
+noRelayStateInResponseMessage=Kein relay state in der Antwort von dem Identity Provider [{0}].
+identityProviderAlreadyLinkedMessage=Die Identität welche von dem Identity Provider [{0}] zurückgegeben wurde, ist bereits mit einem anderen Benutzer verknüpft.
+insufficientPermissionMessage=Nicht genügtend Rechte um die Identität zu verknüpfen.
+couldNotProceedWithAuthenticationRequestMessage=Konnte den Authentifizierungs Request nicht weiter verarbeiten.
+couldNotObtainTokenMessage=Konnte kein token vom Identity Provider [{0}] entnehmen.
+unexpectedErrorRetrievingTokenMessage=Unerwarteter Fehler während dem Empfang des Token von dem Identity Provider [{0}].
+unexpectedErrorHandlingResponseMessage=Unerwarteter Fehler während der bearbeitung des Respons vom Identity Provider [{0}].
+identityProviderAuthenticationFailedMessage=Authentifizierung Fehlgeschlagen. Konnte sich mit dem Identity Provider [{0}] nicht authentifizieren.
+couldNotSendAuthenticationRequestMessage=Konnte Authentifizierungs Request nicht an den Identity Provider [{0}] schiken.
+unexpectedErrorHandlingRequestMessage=Unerwarteter Fehler während der bearbeitung des Requests zum Identity Provider [{0}].
+invalidAccessCodeMessage=Ungültiger Access-Code.
+sessionNotActiveMessage=Session nicht aktiv.
+unknownCodeMessage=Unbekannter Code, bitte melden Sie sich erneut über die Applikation an.
+invalidCodeMessage=Ungültiger Code, bitte melden Sie sich erneut über die Applikation an.
+identityProviderUnexpectedErrorMessage=Unerwarteter Fehler während der Authentifizierung mit dem Identity Provider.
+identityProviderNotFoundMessage=Konnte kein Identity Provider mit der Idenität [{0}] finden.
+realmSupportsNoCredentialsMessage=Realm [{0}] unterstützt keine Credential Typen..
+identityProviderNotUniqueMessage=Realm [{0}] unterstütz mehrere Identity Providers.
+
+invalidParameterMessage=Invalid parameter\: {0}
+missingParameterMessage=Missing parameter\: {0}
+clientNotFoundMessage=Client not found.
+
+emailVerifiedMessage=Ihr E-Mail Addresse wurde erfolgreich verifiziert.
+
+locale_de=Deutsch
+locale_en=Englisch
+
+poweredByKeycloak=Powered by Keycloak
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties
new file mode 100755
index 0000000000..6f48c59dca
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages_en.properties
@@ -0,0 +1,146 @@
+doLogIn=Log in
+doRegister=Register
+doCancel=Cancel
+doSubmit=Submit
+doYes=Yes
+doNo=No
+doForgotPassword=Forgot Password?
+doClickHere=Click here
+
+registerWithTitle=Register with {0}
+registerWithTitleHtml=Register with {0}
+loginTitle=Log in to {0}
+loginTitleHtml=Log in to {0}
+loginOauthTitle=Temporary access for {0}
+loginOauthTitleHtml=Temporary access for {0} requested by {1} .
+loginTotpTitle=Mobile Authenticator Setup
+loginProfileTitle=Update Account Information
+oauthGrantTitle=OAuth Grant
+oauthGrantTitleHtml=Temporary access for {0} requested by {1} .
+errorTitle=We're sorry...
+errorTitleHtml=We're sorry ...
+emailVerifyTitle=Email verification
+emailForgotTitle=Forgot Your Password?
+updatePasswordTitle=Update password
+
+noAccount=New user?
+username=Username
+usernameOrEmail=Username or email
+firstName=First name
+fullName=Full name
+lastName=Last name
+email=Email
+password=Password
+passwordConfirm=Confirm password
+passwordNew=New Password
+passwordNewConfirm=New Password confirmation
+rememberMe=Remember me
+authenticatorCode=One-time code
+street=Street
+locality=City or Locality
+region=State, Province, or Region
+postal_code=Zip or Postal code
+country=Country
+
+loginTotpStep1=Install FreeOTP or Google Authenticator on your mobile
+loginTotpStep2=Open the application and scan the barcode or enter the key
+loginTotpStep3=Enter the one-time code provided by the application and click Submit to finish the setup
+loginTotpOneTime=One-time code
+
+oauthGrantRequest=Do you grant these access privileges?
+
+emailVerifyInstruction1=An email with instructions to verify your email address has been sent to you.
+emailVerifyInstruction2=Haven't received a verification code in your email?
+emailVerifyInstruction3=to re-send the email.
+
+backToLogin=« Back to Login
+
+emailInstruction=Enter your username or email address and we will send you instructions on how to create a new password.
+
+invalidUserMessage=Invalid username or password.
+invalidEmailMessage=Invalid email address.
+accountDisabledMessage=Account is disabled, contact admin.
+accountTemporarilyDisabledMessage=Account is temporarily disabled, contact admin or try again later.
+expiredCodeMessage=Login timeout. Please login again.
+
+missingFirstNameMessage=Please specify first name.
+missingLastNameMessage=Please specify last name.
+missingEmailMessage=Please specify email.
+missingUsernameMessage=Please specify username.
+missingPasswordMessage=Please specify password.
+missingTotpMessage=Please specify authenticator code.
+notMatchPasswordMessage=Passwords don't match.
+
+invalidPasswordExistingMessage=Invalid existing password.
+invalidPasswordConfirmMessage=Password confirmation doesn't match.
+invalidTotpMessage=Invalid authenticator code.
+
+usernameExistsMessage=Username already exists.
+emailExistsMessage=Email already exists.
+
+federatedIdentityEmailExistsMessage=User with email already exists. Please login to account management to link the account.
+federatedIdentityUsernameExistsMessage=User with username already exists. Please login to account management to link the account.
+
+configureTotpMessage=You need to set up Mobile Authenticator to activate your account.
+updateProfileMessage=You need to update your user profile to activate your account.
+updatePasswordMessage=You need to change your password to activate your account.
+verifyEmailMessage=You need to verify your email address to activate your account.
+
+emailSentMessage=You should receive an email shortly with further instructions.
+emailSendErrorMessage=Failed to send email, please try again later
+
+accountUpdatedMessage=Your account has been updated
+accountPasswordUpdatedMessage=Your password has been updated
+
+noAccessMessage=No access
+
+invalidPasswordMinLengthMessage=Invalid password: minimum length {0}
+invalidPasswordMinDigitsMessage=Invalid password: must contain at least {0} numerical digits
+invalidPasswordMinLowerCaseCharsMessage=Invalid password: must contain at least {0} lower case characters
+invalidPasswordMinUpperCaseCharsMessage=Invalid password: must contain at least {0} upper case characters
+invalidPasswordMinSpecialCharsMessage=Invalid password: must contain at least {0} special characters
+invalidPasswordNotUsernameMessage=Invalid password\: must not be equal to the username
+
+failedToProcessResponseMessage=Failed to process response
+httpsRequiredMessage=HTTPS required
+realmNotEnabledMessage=Realm not enabled
+invalidRequestMessage=Invalid Request
+unknownLoginRequesterMessage=Unknown login requester
+loginRequesterNotEnabledMessage=Login requester not enabled
+bearerOnlyMessage=Bearer-only applications are not allowed to initiate browser login
+directGrantsOnlyMessage=Direct-grants-only clients are not allowed to initiate browser login
+invalidRedirectUriMessage=Invalid redirect uri
+unsupportedNameIdFormatMessage=Unsupported NameIDFormat
+invlidRequesterMessage=Invalid requester
+registrationNotAllowedMessage=Registration not allowed
+
+permissionNotApprovedMessage=Permission not approved.
+noRelayStateInResponseMessage=No relay state in response from identity provider [{0}].
+identityProviderAlreadyLinkedMessage=The identity returned by the identity provider [{0}] is already linked to another user.
+insufficientPermissionMessage=Insufficient permissions to link identities.
+couldNotProceedWithAuthenticationRequestMessage=Could not proceed with authentication request to identity provider.
+couldNotObtainTokenMessage=Could not obtain token from identity provider [{0}].
+unexpectedErrorRetrievingTokenMessage=Unexpected error when retrieving token from identity provider [{0}].
+unexpectedErrorHandlingResponseMessage=Unexpected error when handling response from identity provider [{0}].
+identityProviderAuthenticationFailedMessage=Authentication failed. Could not authenticate with identity provider [{0}].
+couldNotSendAuthenticationRequestMessage=Could not send authentication request to identity provider [{0}].
+unexpectedErrorHandlingRequestMessage=Unexpected error when handling authentication request to identity provider [{0}].
+invalidAccessCodeMessage=Invalid access code.
+sessionNotActiveMessage=Session not active.
+unknownCodeMessage=Unknown code, please login again through your application.
+invalidCodeMessage=Invalid code, please login again through your application.
+identityProviderUnexpectedErrorMessage=Unexpected error when authenticating with identity provider
+identityProviderNotFoundMessage=Could not find an identity provider with the identifier [{0}].
+realmSupportsNoCredentialsMessage=Realm [{0}] does not support any credential type.
+identityProviderNotUniqueMessage=Realm [{0}] supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.
+emailVerifiedMessage=Your email address has been verified.
+
+locale_de=German
+locale_en=English
+
+poweredByKeycloak=Powered by Keycloak
+backToApplication=« Back to Application
+missingParameterMessage=Missing parameters\: {0}
+clientNotFoundMessage=Client not found.
+invalidParameterMessage=Invalid parameter\: {0}
+federatedIdentityRegistrationEmailMissingMessage=Email is not provided. Use another provider to create account please.
diff --git a/forms/common-themes/src/main/resources/theme/login/base/register.ftl b/forms/common-themes/src/main/resources/theme/login/base/register.ftl
index 492fbabd52..8dcdcea481 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/register.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/register.ftl
@@ -1,9 +1,9 @@
<#import "template.ftl" as layout>
<@layout.registrationLayout; section>
<#if section = "title">
- ${rb.registerWith} ${realm.name}
+ ${formatter.format(rb.registerWithTitle,(realm.name!''))}
<#elseif section = "header">
- ${rb.registerWith} ${realm.name}
+ ${formatter.format(rb.registerWithTitleHtml,(realm.name!''))}
<#elseif section = "form">
diff --git a/forms/common-themes/src/main/resources/theme/login/base/template.ftl b/forms/common-themes/src/main/resources/theme/login/base/template.ftl
index 49c02469b2..c09271da62 100644
--- a/forms/common-themes/src/main/resources/theme/login/base/template.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/template.ftl
@@ -21,6 +21,19 @@
#list>
#if>
+ <#if realm.internationalizationEnabled>
+
+ #if>
@@ -31,6 +44,15 @@
<#if displayMessage && message?has_content>
diff --git a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
index df43d16fb2..21972b2c00 100755
--- a/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
+++ b/forms/email-freemarker/src/main/java/org/keycloak/email/freemarker/FreeMarkerEmailProvider.java
@@ -5,9 +5,12 @@ import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
import org.keycloak.email.freemarker.beans.EventBean;
import org.keycloak.events.Event;
+import org.keycloak.events.EventType;
import org.keycloak.freemarker.FreeMarkerUtil;
+import org.keycloak.freemarker.LocaleHelper;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
+import org.keycloak.freemarker.beans.TextFormatterBean;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@@ -17,10 +20,7 @@ import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
/**
* @author Stian Thorgersen
@@ -56,7 +56,7 @@ public class FreeMarkerEmailProvider implements EmailProvider {
Map attributes = new HashMap();
attributes.put("event", new EventBean(event));
- send("passwordResetSubject", "event-" + event.getType().toString().toLowerCase() + ".ftl", attributes);
+ send(toCamelCase(event.getType()) + "Subject", "event-" + event.getType().toString().toLowerCase() + ".ftl", attributes);
}
@Override
@@ -81,8 +81,12 @@ public class FreeMarkerEmailProvider implements EmailProvider {
try {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme = themeProvider.getTheme(realm.getEmailTheme(), Theme.Type.EMAIL);
-
- String subject = theme.getMessages().getProperty(subjectKey);
+ Locale locale = LocaleHelper.getLocale(realm, user);
+ attributes.put("locale", locale);
+ Properties rb = theme.getMessages(locale);
+ attributes.put("rb", rb);
+ attributes.put("formatter", new TextFormatterBean(locale));
+ String subject = rb.getProperty(subjectKey);
String body = freeMarker.processTemplate(attributes, template, theme);
send(subject, body);
@@ -150,4 +154,12 @@ public class FreeMarkerEmailProvider implements EmailProvider {
public void close() {
}
+ private String toCamelCase(EventType event){
+ StringBuilder sb = new StringBuilder("event");
+ for(String s : event.name().toString().toLowerCase().split("_")){
+ sb.append(s.substring(0,1).toUpperCase()).append(s.substring(1));
+ }
+ return sb.toString();
+ }
+
}
diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
index 11c26fe767..36a5252515 100755
--- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
+++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
@@ -7,6 +7,7 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -22,6 +23,8 @@ public interface LoginFormsProvider extends Provider {
public LoginFormsProvider setUriInfo(UriInfo uriInfo);
+ public LoginFormsProvider setHttpHeaders(HttpHeaders httpHeaders);
+
public Response createResponse(UserModel.RequiredAction action);
public Response createLogin();
@@ -45,11 +48,11 @@ public interface LoginFormsProvider extends Provider {
public LoginFormsProvider setAccessRequest(List realmRolesRequested, MultivaluedMap resourceRolesRequested);
public LoginFormsProvider setAccessRequest(String message);
- public LoginFormsProvider setError(String message);
+ public LoginFormsProvider setError(String message, Object ... parameters);
- public LoginFormsProvider setSuccess(String message);
+ public LoginFormsProvider setSuccess(String message, Object ... parameters);
- public LoginFormsProvider setWarning(String message);
+ public LoginFormsProvider setWarning(String message, Object ... parameters);
public LoginFormsProvider setUser(UserModel user);
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index be59af04a3..14579b9378 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -5,11 +5,8 @@ import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.keycloak.OAuth2Constants;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
-import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
-import org.keycloak.freemarker.FreeMarkerException;
-import org.keycloak.freemarker.FreeMarkerUtil;
-import org.keycloak.freemarker.Theme;
-import org.keycloak.freemarker.ThemeProvider;
+import org.keycloak.freemarker.*;
+import org.keycloak.freemarker.beans.TextFormatterBean;
import org.keycloak.login.LoginFormsPages;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.login.freemarker.model.ClientBean;
@@ -33,23 +30,17 @@ import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.services.resources.flows.Urls;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.*;
import java.io.IOException;
import java.net.URI;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.text.MessageFormat;
+import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author Stian Thorgersen
*/
-public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
+ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private static final Logger logger = Logger.getLogger(FreeMarkerLoginFormsProvider.class);
@@ -63,6 +54,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private Map httpResponseHeaders = new HashMap();
private String accessRequestMessage;
private URI actionUri;
+ private Object[] parameters;
private String message;
private MessageType messageType = MessageType.ERROR;
@@ -80,6 +72,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private UriInfo uriInfo;
+ private HttpHeaders httpHeaders;
+
public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
this.session = session;
this.freeMarker = freeMarker;
@@ -95,21 +89,27 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return this;
}
+ @Override
+ public LoginFormsProvider setHttpHeaders(HttpHeaders httpHeaders) {
+ this.httpHeaders = httpHeaders;
+ return this;
+ }
+
public Response createResponse(UserModel.RequiredAction action) {
String actionMessage;
LoginFormsPages page;
switch (action) {
case CONFIGURE_TOTP:
- actionMessage = Messages.ACTION_WARN_TOTP;
+ actionMessage = Messages.CONFIGURE_TOTP;
page = LoginFormsPages.LOGIN_CONFIG_TOTP;
break;
case UPDATE_PROFILE:
- actionMessage = Messages.ACTION_WARN_PROFILE;
+ actionMessage = Messages.UPDATE_PROFILE;
page = LoginFormsPages.LOGIN_UPDATE_PROFILE;
break;
case UPDATE_PASSWORD:
- actionMessage = Messages.ACTION_WARN_PASSWD;
+ actionMessage = Messages.UPDATE_PASSWORD;
page = LoginFormsPages.LOGIN_UPDATE_PASSWORD;
break;
case VERIFY_EMAIL:
@@ -123,10 +123,10 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration);
} catch (EmailException e) {
logger.error("Failed to send verification email", e);
- return setError("emailSendError").createErrorPage();
+ return setError(Messages.EMAIL_SENT_ERROR).createErrorPage();
}
- actionMessage = Messages.ACTION_WARN_EMAIL;
+ actionMessage = Messages.VERIFY_EMAIL;
page = LoginFormsPages.LOGIN_VERIFY_EMAIL;
break;
default:
@@ -175,8 +175,13 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
Properties messages;
+ Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, httpHeaders);
+ if(locale != null){
+ attributes.put("locale", locale);
+ attributes.put("formatter", new TextFormatterBean(locale));
+ }
try {
- messages = theme.getMessages();
+ messages = theme.getMessages(locale);
attributes.put("rb", messages);
} catch (IOException e) {
logger.warn("Failed to load messages", e);
@@ -184,7 +189,13 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
if (message != null) {
- attributes.put("message", new MessageBean(messages.containsKey(message) ? messages.getProperty(message) : message, messageType));
+ String formattedMessage;
+ if(messages.containsKey(message)){
+ formattedMessage = new MessageFormat(messages.getProperty(message).replace("'","''"),locale).format(parameters);
+ }else{
+ formattedMessage = message;
+ }
+ attributes.put("message", new MessageBean(formattedMessage, messageType));
}
if (page == LoginFormsPages.OAUTH_GRANT) {
// for some reason Resteasy 2.3.7 doesn't like query params and form params with the same name and will null out the code form param
@@ -233,6 +244,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
for (Map.Entry entry : httpResponseHeaders.entrySet()) {
builder.header(entry.getKey(), entry.getValue());
}
+ LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, Urls.localeCookiePath(baseUri, realm.getName()));
return builder.build();
} catch (FreeMarkerException e) {
logger.error("Failed to process template", e);
@@ -277,21 +289,24 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
return createResponse(LoginFormsPages.CODE);
}
- public FreeMarkerLoginFormsProvider setError(String message) {
+ public FreeMarkerLoginFormsProvider setError(String message, Object ... parameters) {
this.message = message;
this.messageType = MessageType.ERROR;
+ this.parameters = parameters;
return this;
}
- public FreeMarkerLoginFormsProvider setSuccess(String message) {
+ public FreeMarkerLoginFormsProvider setSuccess(String message, Object ... parameters) {
this.message = message;
this.messageType = MessageType.SUCCESS;
+ this.parameters = parameters;
return this;
}
- public FreeMarkerLoginFormsProvider setWarning(String message) {
+ public FreeMarkerLoginFormsProvider setWarning(String message, Object ... parameters) {
this.message = message;
this.messageType = MessageType.WARNING;
+ this.parameters = parameters;
return this;
}
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
index e4ac27f406..3e36d08c9f 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
@@ -25,6 +25,8 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.representations.idm.CredentialRepresentation;
+import java.util.Set;
+
/**
* @author Stian Thorgersen
*/
@@ -60,6 +62,14 @@ public class RealmBean {
return realm.isRememberMe();
}
+ public boolean isInternationalizationEnabled() {
+ return realm.isInternationalizationEnabled();
+ }
+
+ public Set getSupportedLocales(){
+ return realm.getSupportedLocales();
+ }
+
public boolean isPassword() {
for (RequiredCredentialModel r : realm.getRequiredCredentials()) {
if (r.getType().equals(CredentialRepresentation.PASSWORD)) {
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
index 26d67a3bc8..259b09856c 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/UrlBean.java
@@ -86,6 +86,10 @@ public class UrlBean {
return Urls.loginActionEmailVerification(baseURI, realm).toString();
}
+ public String getLocaleCookiePath(){
+ return Urls.localeCookiePath(baseURI, realm);
+ }
+
public String getOauthAction() {
if (this.actionuri != null) {
return this.actionuri.getPath();
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index d8a2141f69..50a13f962a 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -168,13 +168,8 @@ public class AdapterDeploymentContext {
}
@Override
- public String getCodeUrl() {
- return (this.codeUrl != null) ? this.codeUrl : delegate.getCodeUrl();
- }
-
- @Override
- public String getRefreshUrl() {
- return (this.refreshUrl != null) ? this.refreshUrl : delegate.getRefreshUrl();
+ public String getTokenUrl() {
+ return (this.tokenUrl != null) ? this.tokenUrl : delegate.getTokenUrl();
}
@Override
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
index 28b3d7dd1d..2420721bf5 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
@@ -38,7 +38,7 @@ public class AdapterUtils {
return UriUtils.getOrigin(browserRequestURL);
case BROWSER_ONLY:
// Resolve baseURI from the codeURL (This is already non-relative and based on our hostname)
- return UriUtils.getOrigin(deployment.getCodeUrl());
+ return UriUtils.getOrigin(deployment.getTokenUrl());
default:
return "";
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java
index 55dc847bf7..51ddfd5efd 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/BasicAuthRequestAuthenticator.java
@@ -69,8 +69,9 @@ public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticat
try {
HttpPost post = new HttpPost(
KeycloakUriBuilder.fromUri(deployment.getAuthServerBaseUrl())
- .path(ServiceUrlConstants.TOKEN_SERVICE_DIRECT_GRANT_PATH).build(deployment.getRealm()));
+ .path(ServiceUrlConstants.TOKEN_PATH).build(deployment.getRealm()));
java.util.List formparams = new java.util.ArrayList ();
+ formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
formparams.add(new BasicNameValuePair("username", username));
formparams.add(new BasicNameValuePair("password", password));
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index e9dfaf608f..f792046bc4 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -28,8 +28,7 @@ public class KeycloakDeployment {
protected String authServerBaseUrl;
protected String realmInfoUrl;
protected KeycloakUriBuilder authUrl;
- protected String codeUrl;
- protected String refreshUrl;
+ protected String tokenUrl;
protected KeycloakUriBuilder logoutUrl;
protected String accountUrl;
protected String registerNodeUrl;
@@ -131,7 +130,7 @@ public class KeycloakDeployment {
log.debug("resolveBrowserUrls");
}
- String login = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(getRealm()).toString();
+ String login = authUrlBuilder.clone().path(ServiceUrlConstants.AUTH_PATH).build(getRealm()).toString();
authUrl = KeycloakUriBuilder.fromUri(login);
}
@@ -143,11 +142,10 @@ public class KeycloakDeployment {
log.debug("resolveNonBrowserUrls");
}
- refreshUrl = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(getRealm()).toString();
+ tokenUrl = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_PATH).build(getRealm()).toString();
logoutUrl = KeycloakUriBuilder.fromUri(authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH).build(getRealm()).toString());
accountUrl = authUrlBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(getRealm()).toString();
realmInfoUrl = authUrlBuilder.clone().path(ServiceUrlConstants.REALM_INFO_PATH).build(getRealm()).toString();
- codeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(getRealm()).toString();
registerNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_REGISTER_NODE_PATH).build(getRealm()).toString();
unregisterNodeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.CLIENTS_MANAGEMENT_UNREGISTER_NODE_PATH).build(getRealm()).toString();
}
@@ -164,12 +162,8 @@ public class KeycloakDeployment {
return authUrl;
}
- public String getCodeUrl() {
- return codeUrl;
- }
-
- public String getRefreshUrl() {
- return refreshUrl;
+ public String getTokenUrl() {
+ return tokenUrl;
}
public KeycloakUriBuilder getLogoutUrl() {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 9c2129ccf1..be358aa2b0 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -85,7 +85,7 @@ public class KeycloakDeploymentBuilder {
}
deployment.setAuthServerBaseUrl(adapterConfig);
- log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", codeUrl: " + deployment.getCodeUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
+ log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", tokenUrl: " + deployment.getTokenUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
return deployment;
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index c49fa2cf45..90a22047e6 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -136,6 +136,7 @@ public class OAuthRequestAuthenticator {
url = UriUtils.stripQueryParam(url, K_IDP_HINT);
KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
+ .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, url)
.queryParam(OAuth2Constants.STATE, state)
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
index eebac4f91a..27a2949520 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/ServerRequest.java
@@ -87,15 +87,15 @@ public class ServerRequest {
}
public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri, String sessionId) throws HttpFailure, IOException {
- String codeUrl = deployment.getCodeUrl();
+ String tokenUrl = deployment.getTokenUrl();
String client_id = deployment.getResourceName();
Map credentials = deployment.getResourceCredentials();
HttpClient client = deployment.getClient();
- return invokeAccessCodeToToken(client, deployment.isPublicClient(), code, codeUrl, redirectUri, client_id, credentials, sessionId);
+ return invokeAccessCodeToToken(client, deployment.isPublicClient(), code, tokenUrl, redirectUri, client_id, credentials, sessionId);
}
- public static AccessTokenResponse invokeAccessCodeToToken(HttpClient client, boolean publicClient, String code, String codeUrl, String redirectUri, String client_id, Map credentials, String sessionId) throws IOException, HttpFailure {
+ public static AccessTokenResponse invokeAccessCodeToToken(HttpClient client, boolean publicClient, String code, String tokenUrl, String redirectUri, String client_id, Map credentials, String sessionId) throws IOException, HttpFailure {
List formparams = new ArrayList();
redirectUri = stripOauthParametersFromRedirect(redirectUri);
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, "authorization_code"));
@@ -106,7 +106,7 @@ public class ServerRequest {
formparams.add(new BasicNameValuePair(AdapterConstants.APPLICATION_SESSION_HOST, HostUtils.getHostName()));
}
HttpResponse response = null;
- HttpPost post = new HttpPost(codeUrl);
+ HttpPost post = new HttpPost(tokenUrl);
if (!publicClient) {
String clientSecret = credentials.get(CredentialRepresentation.SECRET);
if (clientSecret != null) {
@@ -152,15 +152,15 @@ public class ServerRequest {
}
public static AccessTokenResponse invokeRefresh(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
- String refreshUrl = deployment.getRefreshUrl();
+ String tokenUrl = deployment.getTokenUrl();
String client_id = deployment.getResourceName();
Map credentials = deployment.getResourceCredentials();
HttpClient client = deployment.getClient();
- return invokeRefresh(client, deployment.isPublicClient(), refreshToken, refreshUrl, client_id, credentials);
+ return invokeRefresh(client, deployment.isPublicClient(), refreshToken, tokenUrl, client_id, credentials);
}
- public static AccessTokenResponse invokeRefresh(HttpClient client, boolean publicClient, String refreshToken, String refreshUrl, String client_id, Map credentials) throws IOException, HttpFailure {
+ public static AccessTokenResponse invokeRefresh(HttpClient client, boolean publicClient, String refreshToken, String tokenUrl, String client_id, Map credentials) throws IOException, HttpFailure {
List formparams = new ArrayList();
for (Map.Entry entry : credentials.entrySet()) {
formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
@@ -168,7 +168,7 @@ public class ServerRequest {
formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
HttpResponse response = null;
- HttpPost post = new HttpPost(refreshUrl);
+ HttpPost post = new HttpPost(tokenUrl);
if (!publicClient) {
String clientSecret = credentials.get(CredentialRepresentation.SECRET);
if (clientSecret != null) {
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
index da76aae422..a11e1ee4a3 100644
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
@@ -64,10 +64,11 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
protected Auth directGrantAuth(String username, String password) throws IOException, VerificationException {
String authServerBaseUrl = deployment.getAuthServerBaseUrl();
- URI directGrantUri = KeycloakUriBuilder.fromUri(authServerBaseUrl).path(ServiceUrlConstants.TOKEN_SERVICE_DIRECT_GRANT_PATH).build(deployment.getRealm());
+ URI directGrantUri = KeycloakUriBuilder.fromUri(authServerBaseUrl).path(ServiceUrlConstants.TOKEN_PATH).build(deployment.getRealm());
HttpPost post = new HttpPost(directGrantUri);
List formparams = new ArrayList();
+ formparams.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
formparams.add(new BasicNameValuePair("username", username));
formparams.add(new BasicNameValuePair("password", password));
diff --git a/integration/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java b/integration/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
index 40390f9968..a40b83ec3d 100644
--- a/integration/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
+++ b/integration/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
@@ -20,7 +20,7 @@ public class KeycloakDeploymentBuilderTest {
assertEquals("demo", deployment.getRealm());
assertEquals("customer-portal", deployment.getResourceName());
assertEquals(PemUtils.decodePublicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"), deployment.getRealmKey());
- assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/login", deployment.getAuthUrl().build().toString());
+ assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/auth", deployment.getAuthUrl().build().toString());
assertEquals(SslRequired.EXTERNAL, deployment.getSslRequired());
assertTrue(deployment.isUseResourceRoleMappings());
assertTrue(deployment.isCors());
@@ -33,7 +33,7 @@ public class KeycloakDeploymentBuilderTest {
assertTrue(deployment.isExposeToken());
assertEquals("234234-234234-234234", deployment.getResourceCredentials().get("secret"));
assertEquals(20, ((ThreadSafeClientConnManager) deployment.getClient().getConnectionManager()).getMaxTotal());
- assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/refresh", deployment.getRefreshUrl());
+ assertEquals("https://localhost:8443/auth/realms/demo/protocol/openid-connect/token", deployment.getTokenUrl());
assertTrue(deployment.isAlwaysRefreshToken());
assertTrue(deployment.isRegisterNodeAtStartup());
assertEquals(1000, deployment.getRegisterNodePeriod());
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 1488d38f3c..20914e5de0 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -20,9 +20,10 @@ public class Keycloak {
private Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret){
config = new Config(serverUrl, realm, username, password, clientId, clientSecret);
- tokenManager = new TokenManager(config);
-
client = new ResteasyClientBuilder().build();
+
+ tokenManager = new TokenManager(config, client);
+
target = client.target(config.getServerUrl());
target.register(new BearerAuthFilter(tokenManager.getAccessTokenString()));
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
index 3e3d923ea2..f5a796dd24 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
@@ -18,10 +18,12 @@ public class TokenManager {
private AccessTokenResponse currentToken;
private Date expirationTime;
- private Config config;
+ private final Config config;
+ private final ResteasyClient client;
- public TokenManager(Config config){
+ public TokenManager(Config config, ResteasyClient client){
this.config = config;
+ this.client = client;
}
public String getAccessTokenString(){
@@ -38,7 +40,6 @@ public class TokenManager {
}
public AccessTokenResponse grantToken(){
- ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(config.getServerUrl());
Form form = new Form()
@@ -60,7 +61,6 @@ public class TokenManager {
}
public AccessTokenResponse refreshToken(){
- ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(config.getServerUrl());
Form form = new Form()
diff --git a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
index d3ed5367cb..e69f6c82db 100644
--- a/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
+++ b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
@@ -97,6 +97,7 @@ public class KeycloakInstalled {
String state = UUID.randomUUID().toString();
String authUrl = deployment.getAuthUrl().clone()
+ .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
.queryParam(OAuth2Constants.STATE, state)
@@ -153,6 +154,7 @@ public class KeycloakInstalled {
String redirectUri = "urn:ietf:wg:oauth:2.0:oob";
String authUrl = deployment.getAuthUrl().clone()
+ .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
.build().toString();
diff --git a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
index 6944782e2d..04ef9a2246 100755
--- a/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
+++ b/integration/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
@@ -53,7 +53,7 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
for (Map.Entry entry : credentials.entrySet()) {
codeForm.param(entry.getKey(), entry.getValue());
}
- Response res = client.target(codeUrl).request().post(Entity.form(codeForm));
+ Response res = client.target(tokenUrl).request().post(Entity.form(codeForm));
try {
if (res.getStatus() == 400) {
throw new BadRequestException();
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index 1b0813b0ed..34118c251f 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -140,7 +140,7 @@
sessionStorage.oauthState = JSON.stringify({ state: state, redirectUri: encodeURIComponent(redirectUri) });
- var action = 'login';
+ var action = 'auth';
if (options && options.action == 'register') {
action = 'registrations';
}
@@ -284,7 +284,7 @@
promise.setSuccess(false);
} else {
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
- var url = getRealmUrl() + '/protocol/openid-connect/refresh';
+ var url = getRealmUrl() + '/protocol/openid-connect/token';
refreshQueue.push(promise);
@@ -358,8 +358,8 @@
var prompt = oauth.prompt;
if (code) {
- var params = 'code=' + code;
- var url = getRealmUrl() + '/protocol/openid-connect/access/codes';
+ var params = 'code=' + code + '&grant_type=authorization_code';
+ var url = getRealmUrl() + '/protocol/openid-connect/token';
var req = new XMLHttpRequest();
req.open('POST', url, true);
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 2420c5308a..390721dadb 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -42,7 +42,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
private AccessTokenResponse resolveBearerToken(HttpServletRequest request, String redirectUri, String code) throws IOException, ServerRequest.HttpFailure {
// Don't send sessionId in oauth clients for now
- return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, codeUrl, false), redirectUri, clientId, credentials, null);
+ return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, tokenUrl, false), redirectUri, clientId, credentials, null);
}
/**
@@ -148,7 +148,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
}
public AccessTokenResponse refreshToken(HttpServletRequest request, String refreshToken) throws IOException, ServerRequest.HttpFailure {
- return ServerRequest.invokeRefresh(client, publicClient, refreshToken, getUrl(request, refreshUrl, false), clientId, credentials);
+ return ServerRequest.invokeRefresh(client, publicClient, refreshToken, getUrl(request, tokenUrl, false), clientId, credentials);
}
public static IDToken extractIdToken(String idToken) {
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
index 5620636aeb..d642e5c78b 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
@@ -54,25 +54,20 @@ public class ServletOAuthClientBuilder {
RelativeUrlsUsed useRelative = relativeUrls(serverBuilder, adapterConfig);
oauthClient.setRelativeUrlsUsed(useRelative);
- String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
+ String authUrl = serverBuilder.clone().path(ServiceUrlConstants.AUTH_PATH).build(adapterConfig.getRealm()).toString();
KeycloakUriBuilder tokenUrlBuilder;
- KeycloakUriBuilder refreshUrlBuilder;
if (useRelative == RelativeUrlsUsed.BROWSER_ONLY) {
// Use absolute URI for refreshToken and codeToToken requests
KeycloakUriBuilder nonBrowsersServerBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrlForBackendRequests());
tokenUrlBuilder = nonBrowsersServerBuilder.clone();
- refreshUrlBuilder = nonBrowsersServerBuilder.clone();
} else {
tokenUrlBuilder = serverBuilder.clone();
- refreshUrlBuilder = serverBuilder.clone();
}
- String tokenUrl = tokenUrlBuilder.path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
- String refreshUrl = refreshUrlBuilder.path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
+ String tokenUrl = tokenUrlBuilder.path(ServiceUrlConstants.TOKEN_PATH).build(adapterConfig.getRealm()).toString();
oauthClient.setAuthUrl(authUrl);
- oauthClient.setCodeUrl(tokenUrl);
- oauthClient.setRefreshUrl(refreshUrl);
+ oauthClient.setTokenUrl(tokenUrl);
}
private static RelativeUrlsUsed relativeUrls(KeycloakUriBuilder serverBuilder, AdapterConfig adapterConfig) {
diff --git a/model/api/src/main/java/org/keycloak/models/ModelException.java b/model/api/src/main/java/org/keycloak/models/ModelException.java
index 1c2f068dad..d3431b056b 100644
--- a/model/api/src/main/java/org/keycloak/models/ModelException.java
+++ b/model/api/src/main/java/org/keycloak/models/ModelException.java
@@ -5,6 +5,8 @@ package org.keycloak.models;
*/
public class ModelException extends RuntimeException {
+ private Object[] parameters;
+
public ModelException() {
}
@@ -12,6 +14,11 @@ public class ModelException extends RuntimeException {
super(message);
}
+ public ModelException(String message, Object ... parameters) {
+ super(message);
+ this.parameters = parameters;
+ }
+
public ModelException(String message, Throwable cause) {
super(message, cause);
}
@@ -20,4 +27,11 @@ public class ModelException extends RuntimeException {
super(cause);
}
+ public Object[] getParameters() {
+ return parameters;
+ }
+
+ public void setParameters(Object[] parameters) {
+ this.parameters = parameters;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
index dc82bcc5f5..cfcc108db8 100755
--- a/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/model/api/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -1,5 +1,6 @@
package org.keycloak.models;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -9,6 +10,13 @@ import java.util.List;
*/
public class PasswordPolicy {
+ public static final String INVALID_PASSWORD_MIN_LENGTH_MESSAGE = "invalidPasswordMinLengthMessage";
+ public static final String INVALID_PASSWORD_MIN_DIGITS_MESSAGE = "invalidPasswordMinDigitsMessage";
+ public static final String INVALID_PASSWORD_MIN_LOWER_CASE_CHARS_MESSAGE = "invalidPasswordMinLowerCaseCharsMessage";
+ public static final String INVALID_PASSWORD_MIN_UPPER_CASE_CHARS_MESSAGE = "invalidPasswordMinUpperCaseCharsMessage";
+ public static final String INVALID_PASSWORD_MIN_SPECIAL_CHARS_MESSAGE = "invalidPasswordMinSpecialCharsMessage";
+ public static final String INVALID_PASSWORD_NOT_USERNAME = "invalidPasswordNotUsernameMessage";
+
private List policies;
private String policyString;
@@ -52,6 +60,8 @@ public class PasswordPolicy {
list.add(new UpperCase(args));
} else if (name.equals(SpecialChars.NAME)) {
list.add(new SpecialChars(args));
+ } else if (name.equals(NotUsername.NAME)) {
+ list.add(new NotUsername(args));
} else if (name.equals(HashIterations.NAME)) {
list.add(new HashIterations(args));
}
@@ -74,9 +84,9 @@ public class PasswordPolicy {
return -1;
}
- public String validate(String password) {
+ public Error validate(String username, String password) {
for (Policy p : policies) {
- String error = p.validate(password);
+ Error error = p.validate(username, password);
if (error != null) {
return error;
}
@@ -85,7 +95,25 @@ public class PasswordPolicy {
}
private static interface Policy {
- public String validate(String password);
+ public Error validate(String username, String password);
+ }
+
+ public static class Error{
+ private String message;
+ private Object[] parameters;
+
+ private Error(String message, Object ... parameters){
+ this.message = message;
+ this.parameters = parameters;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Object[] getParameters() {
+ return parameters;
+ }
}
private static class HashIterations implements Policy {
@@ -97,11 +125,23 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
+ public Error validate(String username, String password) {
return null;
}
}
+ private static class NotUsername implements Policy {
+ private static final String NAME = "notUsername";
+
+ public NotUsername(String[] args) {
+ }
+
+ @Override
+ public Error validate(String username, String password) {
+ return username.equals(password) ? new Error(INVALID_PASSWORD_NOT_USERNAME) : null;
+ }
+ }
+
private static class Length implements Policy {
private static final String NAME = "length";
private int min;
@@ -111,8 +151,8 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
- return password.length() < min ? "Invalid password: minimum length " + min : null;
+ public Error validate(String username, String password) {
+ return password.length() < min ? new Error(INVALID_PASSWORD_MIN_LENGTH_MESSAGE, min) : null;
}
}
@@ -125,14 +165,14 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
+ public Error validate(String username, String password) {
int count = 0;
for (char c : password.toCharArray()) {
if (Character.isDigit(c)) {
count++;
}
}
- return count < min ? "Invalid password: must contain at least " + min + " numerical digits" : null;
+ return count < min ? new Error(INVALID_PASSWORD_MIN_DIGITS_MESSAGE, min) : null;
}
}
@@ -145,14 +185,14 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
+ public Error validate(String username, String password) {
int count = 0;
for (char c : password.toCharArray()) {
if (Character.isLowerCase(c)) {
count++;
}
}
- return count < min ? "Invalid password: must contain at least " + min + " lower case characters": null;
+ return count < min ? new Error(INVALID_PASSWORD_MIN_LOWER_CASE_CHARS_MESSAGE, min): null;
}
}
@@ -165,14 +205,14 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
+ public Error validate(String username, String password) {
int count = 0;
for (char c : password.toCharArray()) {
if (Character.isUpperCase(c)) {
count++;
}
}
- return count < min ? "Invalid password: must contain at least " + min + " upper case characters" : null;
+ return count < min ? new Error(INVALID_PASSWORD_MIN_UPPER_CASE_CHARS_MESSAGE, min) : null;
}
}
@@ -185,14 +225,14 @@ public class PasswordPolicy {
}
@Override
- public String validate(String password) {
+ public Error validate(String username, String password) {
int count = 0;
for (char c : password.toCharArray()) {
if (!Character.isLetterOrDigit(c)) {
count++;
}
}
- return count < min ? "Invalid password: must contain at least " + min + " special characters" : null;
+ return count < min ? new Error(INVALID_PASSWORD_MIN_SPECIAL_CHARS_MESSAGE, min) : null;
}
}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index ab260a13a3..7308565573 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -244,4 +244,11 @@ public interface RealmModel extends RoleContainerModel {
ClientModel findClientById(String id);
boolean isIdentityFederationEnabled();
+
+ boolean isInternationalizationEnabled();
+ void setInternationalizationEnabled(boolean enabled);
+ Set getSupportedLocales();
+ void setSupportedLocales(Set locales);
+ String getDefaultLocale();
+ void setDefaultLocale(String locale);
}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
index fe96e5af16..1016341e3a 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
@@ -323,8 +323,8 @@ public class UserFederationManager implements UserProvider {
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (realm.getPasswordPolicy() != null) {
- String error = realm.getPasswordPolicy().validate(credential.getValue());
- if (error != null) throw new ModelException(error);
+ PasswordPolicy.Error error = realm.getPasswordPolicy().validate(user.getUsername(), credential.getValue());
+ if (error != null) throw new ModelException(error.getMessage(), error.getParameters());
}
}
user.updateCredential(credential);
diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java
index 1047ad252b..ee8ce80d0c 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -13,6 +13,7 @@ public interface UserModel {
public static final String LAST_NAME = "lastName";
public static final String FIRST_NAME = "firstName";
public static final String EMAIL = "email";
+ public static final String LOCALE = "locale";
String getId();
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index 38baa89319..678fb3326a 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -65,6 +65,10 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private String adminAppId;
+ private boolean internationalizationEnabled;
+ private List supportedLocales = new ArrayList();
+ private String defaultLocale;
+
public String getName() {
return name;
}
@@ -407,6 +411,30 @@ public class RealmEntity extends AbstractIdentifiableEntity {
public void setCertificatePem(String certificatePem) {
this.certificatePem = certificatePem;
}
+
+ public boolean isInternationalizationEnabled() {
+ return internationalizationEnabled;
+ }
+
+ public void setInternationalizationEnabled(boolean internationalizationEnabled) {
+ this.internationalizationEnabled = internationalizationEnabled;
+ }
+
+ public List getSupportedLocales() {
+ return supportedLocales;
+ }
+
+ public void setSupportedLocales(List supportedLocales) {
+ this.supportedLocales = supportedLocales;
+ }
+
+ public String getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public void setDefaultLocale(String defaultLocale) {
+ this.defaultLocale = defaultLocale;
+ }
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 686eede868..736aff8b12 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -155,6 +155,10 @@ public class ModelToRepresentation {
rep.addIdentityProvider(toRepresentation(provider));
}
+ rep.setInternationalizationEnabled(realm.isInternationalizationEnabled());
+ rep.getSupportedLocales().addAll(realm.getSupportedLocales());
+ rep.setDefaultLocale(realm.getDefaultLocale());
+
return rep;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index ce87adae13..c2090d3ce9 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -243,6 +243,16 @@ public class RepresentationToModel {
UserModel user = createUser(session, newRealm, userRep, appMap);
}
}
+
+ if(rep.isInternationalizationEnabled() != null){
+ newRealm.setInternationalizationEnabled(rep.isInternationalizationEnabled());
+ }
+ if(rep.getSupportedLocales() != null){
+ newRealm.setSupportedLocales(new HashSet(rep.getSupportedLocales()));
+ }
+ if(rep.getDefaultLocale() != null){
+ newRealm.setDefaultLocale(rep.getDefaultLocale());
+ }
}
public static void updateRealm(RealmRepresentation rep, RealmModel realm) {
@@ -304,6 +314,16 @@ public class RepresentationToModel {
if ("GENERATE".equals(rep.getPublicKey())) {
KeycloakModelUtils.generateRealmKeys(realm);
}
+
+ if(rep.isInternationalizationEnabled() != null){
+ realm.setInternationalizationEnabled(rep.isInternationalizationEnabled());
+ }
+ if(rep.getSupportedLocales() != null){
+ realm.setSupportedLocales(new HashSet(rep.getSupportedLocales()));
+ }
+ if(rep.getDefaultLocale() != null){
+ realm.setDefaultLocale(rep.getDefaultLocale());
+ }
}
// Basic realm stuff
diff --git a/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java b/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
index 3481498884..3bde361113 100644
--- a/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
+++ b/model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
@@ -11,68 +11,86 @@ public class PasswordPolicyTest {
@Test
public void testLength() {
PasswordPolicy policy = new PasswordPolicy("length");
- Assert.assertEquals("Invalid password: minimum length 8", policy.validate("1234567"));
- Assert.assertNull(policy.validate("12345678"));
+ Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate("jdoe", "1234567").getMessage());
+ Assert.assertArrayEquals(new Object[]{8}, policy.validate("jdoe", "1234567").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "12345678"));
policy = new PasswordPolicy("length(4)");
- Assert.assertEquals("Invalid password: minimum length 4", policy.validate("123"));
- Assert.assertNull(policy.validate("1234"));
+ Assert.assertEquals("invalidPasswordMinLengthMessage", policy.validate("jdoe", "123").getMessage());
+ Assert.assertArrayEquals(new Object[]{4}, policy.validate("jdoe", "123").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "1234"));
}
@Test
public void testDigits() {
PasswordPolicy policy = new PasswordPolicy("digits");
- Assert.assertEquals("Invalid password: must contain at least 1 numerical digits", policy.validate("abcd"));
- Assert.assertNull(policy.validate("abcd1"));
+ Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate("jdoe", "abcd").getMessage());
+ Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "abcd1"));
policy = new PasswordPolicy("digits(2)");
- Assert.assertEquals("Invalid password: must contain at least 2 numerical digits", policy.validate("abcd1"));
- Assert.assertNull(policy.validate("abcd12"));
+ Assert.assertEquals("invalidPasswordMinDigitsMessage", policy.validate("jdoe", "abcd1").getMessage());
+ Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "abcd1").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "abcd12"));
}
@Test
public void testLowerCase() {
PasswordPolicy policy = new PasswordPolicy("lowerCase");
- Assert.assertEquals("Invalid password: must contain at least 1 lower case characters", policy.validate("ABCD1234"));
- Assert.assertNull(policy.validate("ABcD1234"));
+ Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate("jdoe", "ABCD1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "ABCD1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "ABcD1234"));
policy = new PasswordPolicy("lowerCase(2)");
- Assert.assertEquals("Invalid password: must contain at least 2 lower case characters", policy.validate("ABcD1234"));
- Assert.assertNull(policy.validate("aBcD1234"));
+ Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policy.validate("jdoe", "ABcD1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "ABcD1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "aBcD1234"));
}
@Test
public void testUpperCase() {
PasswordPolicy policy = new PasswordPolicy("upperCase");
- Assert.assertEquals("Invalid password: must contain at least 1 upper case characters", policy.validate("abcd1234"));
- Assert.assertNull(policy.validate("abCd1234"));
+ Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate("jdoe", "abcd1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "abCd1234"));
policy = new PasswordPolicy("upperCase(2)");
- Assert.assertEquals("Invalid password: must contain at least 2 upper case characters", policy.validate("abCd1234"));
- Assert.assertNull(policy.validate("AbCd1234"));
+ Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policy.validate("jdoe", "abCd1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "abCd1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "AbCd1234"));
}
@Test
public void testSpecialChars() {
PasswordPolicy policy = new PasswordPolicy("specialChars");
- Assert.assertEquals("Invalid password: must contain at least 1 special characters", policy.validate("abcd1234"));
- Assert.assertNull(policy.validate("ab&d1234"));
+ Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate("jdoe", "abcd1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{1}, policy.validate("jdoe", "abcd1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "ab&d1234"));
policy = new PasswordPolicy("specialChars(2)");
- Assert.assertEquals("Invalid password: must contain at least 2 special characters", policy.validate("ab&d1234"));
- Assert.assertNull(policy.validate("ab&d-234"));
+ Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policy.validate("jdoe", "ab&d1234").getMessage());
+ Assert.assertArrayEquals(new Object[]{2}, policy.validate("jdoe", "ab&d1234").getParameters());
+ Assert.assertNull(policy.validate("jdoe", "ab&d-234"));
+ }
+
+ @Test
+ public void testNotUsername() {
+ PasswordPolicy policy = new PasswordPolicy("notUsername");
+ Assert.assertEquals("invalidPasswordNotUsernameMessage", policy.validate("jdoe", "jdoe").getMessage());
+ Assert.assertNull(policy.validate("jdoe", "ab&d1234"));
}
@Test
public void testComplex() {
- PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2)");
- Assert.assertNotNull(policy.validate("12aaBB&"));
- Assert.assertNotNull(policy.validate("aaaaBB&-"));
- Assert.assertNotNull(policy.validate("12AABB&-"));
- Assert.assertNotNull(policy.validate("12aabb&-"));
- Assert.assertNotNull(policy.validate("12aaBBcc"));
+ PasswordPolicy policy = new PasswordPolicy("length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2) and notUsername()");
+ Assert.assertNotNull(policy.validate("jdoe", "12aaBB&"));
+ Assert.assertNotNull(policy.validate("jdoe", "aaaaBB&-"));
+ Assert.assertNotNull(policy.validate("jdoe", "12AABB&-"));
+ Assert.assertNotNull(policy.validate("jdoe", "12aabb&-"));
+ Assert.assertNotNull(policy.validate("jdoe", "12aaBBcc"));
+ Assert.assertNotNull(policy.validate("12aaBB&-", "12aaBB&-"));
- Assert.assertNull(policy.validate("12aaBB&-"));
+ Assert.assertNull(policy.validate("jdoe", "12aaBB&-"));
}
}
diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
index 5183b74735..99ab488fe4 100755
--- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
+++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java
@@ -1067,6 +1067,36 @@ public class RealmAdapter implements RealmModel {
realm.setAccessCodeLifespanLogin(accessCodeLifespanLogin);
}
+ @Override
+ public boolean isInternationalizationEnabled() {
+ return realm.isInternationalizationEnabled();
+ }
+
+ @Override
+ public void setInternationalizationEnabled(boolean enabled) {
+ realm.setInternationalizationEnabled(enabled);
+ }
+
+ @Override
+ public Set getSupportedLocales() {
+ return new HashSet<>(realm.getSupportedLocales());
+ }
+
+ @Override
+ public void setSupportedLocales(Set locales) {
+ realm.setSupportedLocales(new ArrayList<>(locales));
+ }
+
+ @Override
+ public String getDefaultLocale() {
+ return realm.getDefaultLocale();
+ }
+
+ @Override
+ public void setDefaultLocale(String locale) {
+ realm.setDefaultLocale(locale);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index a58774d369..77b84e64aa 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -888,4 +888,39 @@ public class RealmAdapter implements RealmModel {
public int hashCode() {
return getId().hashCode();
}
+
+ @Override
+ public boolean isInternationalizationEnabled() {
+ if (updated != null) return updated.isInternationalizationEnabled();
+ return cached.isInternationalizationEnabled();
+ }
+
+ @Override
+ public void setInternationalizationEnabled(boolean enabled) {
+ getDelegateForUpdate();
+ updated.setInternationalizationEnabled(enabled);
+ }
+
+ @Override
+ public Set getSupportedLocales() {
+ if (updated != null) return updated.getSupportedLocales();
+ return cached.getSupportedLocales();
+ }
+
+ @Override
+ public void setSupportedLocales(Set locales) {
+ getDelegateForUpdate();
+ updated.setSupportedLocales(locales);
+ }
+
+ @Override
+ public String getDefaultLocale() {
+ if (updated != null) return updated.getDefaultLocale();
+ return cached.getDefaultLocale();
+ }
+
+ @Override
+ public void setDefaultLocale(String locale) {
+ updated.setDefaultLocale(locale);
+ }
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index dc062401c6..a4ce5bb653 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -83,6 +83,9 @@ public class CachedRealm {
private Map realmRoles = new HashMap();
private Map applications = new HashMap();
private Map clients = new HashMap();
+ private boolean internationalizationEnabled;
+ private Set supportedLocales = new HashSet();
+ private String defaultLocale;
public CachedRealm() {
}
@@ -164,6 +167,10 @@ public class CachedRealm {
cache.addCachedOAuthClient(cachedApp);
}
+ internationalizationEnabled = model.isInternationalizationEnabled();
+ supportedLocales.addAll(model.getSupportedLocales());
+ defaultLocale = model.getDefaultLocale();
+
}
@@ -353,4 +360,16 @@ public class CachedRealm {
public List getIdentityProviders() {
return identityProviders;
}
+
+ public boolean isInternationalizationEnabled() {
+ return internationalizationEnabled;
+ }
+
+ public Set getSupportedLocales() {
+ return supportedLocales;
+ }
+
+ public String getDefaultLocale() {
+ return defaultLocale;
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index a17dd1791d..73add51137 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -1238,4 +1238,36 @@ public class RealmAdapter implements RealmModel {
return !this.realm.getIdentityProviders().isEmpty();
}
+ @Override
+ public boolean isInternationalizationEnabled() {
+ return realm.isInternationalizationEnabled();
+ }
+
+ @Override
+ public void setInternationalizationEnabled(boolean enabled) {
+ realm.setInternationalizationEnabled(enabled);
+ em.flush();
+ }
+
+ @Override
+ public Set getSupportedLocales() {
+ return realm.getSupportedLocales();
+ }
+
+ @Override
+ public void setSupportedLocales(Set locales) {
+ realm.setSupportedLocales(locales);
+ em.flush();
+ }
+
+ @Override
+ public String getDefaultLocale() {
+ return realm.getDefaultLocale();
+ }
+
+ @Override
+ public void setDefaultLocale(String locale) {
+ realm.setDefaultLocale(locale);
+ em.flush();
+ }
}
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 1ba7a5573c..563791eaa0 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -137,6 +137,18 @@ public class RealmEntity {
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
protected List identityProviders = new ArrayList();
+ @Column(name="INTERNATIONALIZATION_ENABLED")
+ protected boolean internationalizationEnabled;
+
+ @ElementCollection
+ @Column(name="VALUE")
+ @CollectionTable(name="REALM_SUPPORTED_LOCALES", joinColumns={ @JoinColumn(name="REALM_ID") })
+ protected Set supportedLocales = new HashSet();
+
+ @Column(name="DEFAULT_LOCALE")
+ protected String defaultLocale;
+
+
public String getId() {
return id;
}
@@ -452,5 +464,28 @@ public class RealmEntity {
getIdentityProviders().add(entity);
}
+ public boolean isInternationalizationEnabled() {
+ return internationalizationEnabled;
+ }
+
+ public void setInternationalizationEnabled(boolean internationalizationEnabled) {
+ this.internationalizationEnabled = internationalizationEnabled;
+ }
+
+ public Set getSupportedLocales() {
+ return supportedLocales;
+ }
+
+ public void setSupportedLocales(Set supportedLocales) {
+ this.supportedLocales = supportedLocales;
+ }
+
+ public String getDefaultLocale() {
+ return defaultLocale;
+ }
+
+ public void setDefaultLocale(String defaultLocale) {
+ this.defaultLocale = defaultLocale;
+ }
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 9bee5a52c0..655a45293c 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -1085,5 +1085,40 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
return getId().hashCode();
}
+ @Override
+ public boolean isInternationalizationEnabled() {
+ return realm.isInternationalizationEnabled();
+ }
+ @Override
+ public void setInternationalizationEnabled(boolean enabled) {
+ realm.setInternationalizationEnabled(enabled);
+ updateRealm();
+ }
+
+ @Override
+ public Set getSupportedLocales() {
+ return new HashSet(realm.getSupportedLocales());
+ }
+
+ @Override
+ public void setSupportedLocales(Set locales) {
+ if (locales != null) {
+ realm.setEventsListeners(new ArrayList(locales));
+ } else {
+ realm.setEventsListeners(Collections.EMPTY_LIST);
+ }
+ updateRealm();
+ }
+
+ @Override
+ public String getDefaultLocale() {
+ return realm.getDefaultLocale();
+ }
+
+ @Override
+ public void setDefaultLocale(String locale) {
+ realm.setDefaultLocale(locale);
+ updateRealm();
+ }
}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 183ebd571c..0e4b089385 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -22,6 +22,7 @@ import org.keycloak.protocol.saml.mappers.SAMLLoginResponseMapper;
import org.keycloak.protocol.saml.mappers.SAMLRoleListMapper;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ResourceAdminManager;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.admin.ClientAttributeCertificateResource;
import org.keycloak.services.resources.flows.Flows;
@@ -94,6 +95,7 @@ public class SamlProtocol implements LoginProtocol {
protected UriInfo uriInfo;
+ protected HttpHeaders headers;
@Override
@@ -114,6 +116,12 @@ public class SamlProtocol implements LoginProtocol {
return this;
}
+ @Override
+ public SamlProtocol setHttpHeaders(HttpHeaders headers){
+ this.headers = headers;
+ return this;
+ }
+
@Override
public Response cancelLogin(ClientSessionModel clientSession) {
return getErrorResponse(clientSession, JBossSAMLURIConstants.STATUS_REQUEST_DENIED.get());
@@ -141,7 +149,7 @@ public class SamlProtocol implements LoginProtocol {
return builder.redirectBinding().response();
}
} catch (Exception e) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE );
}
}
@@ -295,7 +303,7 @@ public class SamlProtocol implements LoginProtocol {
samlDocument = builder.buildDocument(samlModel);
} catch (Exception e) {
logger.error("failed", e);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo,headers, Messages.FAILED_TO_PROCESS_RESPONSE);
}
SAML2BindingBuilder2 bindingBuilder = new SAML2BindingBuilder2();
@@ -317,7 +325,7 @@ public class SamlProtocol implements LoginProtocol {
publicKey = SamlProtocolUtils.getEncryptionValidationKey(client);
} catch (Exception e) {
logger.error("failed", e);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE);
}
bindingBuilder.encrypt(publicKey);
}
@@ -329,7 +337,7 @@ public class SamlProtocol implements LoginProtocol {
}
} catch (Exception e) {
logger.error("failed", e);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.FAILED_TO_PROCESS_RESPONSE );
}
}
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
index 80420318ba..3e7cd2f300 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -23,6 +23,7 @@ import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.HttpAuthenticationManager;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.util.StreamUtil;
@@ -106,18 +107,18 @@ public class SamlService {
if (!checkSsl()) {
event.event(EventType.LOGIN);
event.error(Errors.SSL_REQUIRED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED );
}
if (!realm.isEnabled()) {
event.event(EventType.LOGIN_ERROR);
event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
if (samlRequest == null && samlResponse == null) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST );
}
return null;
@@ -131,7 +132,7 @@ public class SamlService {
if (!uriInfo.getAbsolutePath().toString().equals(statusResponse.getDestination())) {
event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE);
event.detail(Details.REASON, "invalid_destination");
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid request.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
@@ -139,7 +140,7 @@ public class SamlService {
logger.warn("Unknown saml response.");
event.event(EventType.LOGOUT);
event.error(Errors.INVALID_TOKEN);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
// assume this is a logout response
UserSessionModel userSession = authResult.getSession();
@@ -148,10 +149,10 @@ public class SamlService {
logger.warn("UserSession is not tagged as logging out.");
event.event(EventType.LOGOUT);
event.error(Errors.INVALID_SAML_LOGOUT_RESPONSE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
logger.debug("logout response");
- Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection);
+ Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
event.success();
return response;
}
@@ -161,7 +162,7 @@ public class SamlService {
if (documentHolder == null) {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
SAML2Object samlObject = documentHolder.getSamlObject();
@@ -173,23 +174,23 @@ public class SamlService {
if (client == null) {
event.event(EventType.LOGIN);
event.error(Errors.CLIENT_NOT_FOUND);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown login requester.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
event.event(EventType.LOGIN);
event.error(Errors.CLIENT_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Login requester not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
if ((client instanceof ApplicationModel) && ((ApplicationModel)client).isBearerOnly()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Bearer-only applications are not allowed to initiate browser login");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.BEARER_ONLY);
}
if (client.isDirectGrantsOnly()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "direct-grants-only clients are not allowed to initiate browser login");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.DIRECT_GRANTS_ONLY );
}
try {
@@ -198,7 +199,7 @@ public class SamlService {
SamlService.logger.error("request validation failed", e);
event.event(EventType.LOGIN);
event.error(Errors.INVALID_SIGNATURE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid requester.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUESTER);
}
logger.debug("verified request");
if (samlObject instanceof AuthnRequestType) {
@@ -216,7 +217,7 @@ public class SamlService {
} else {
event.event(EventType.LOGIN);
event.error(Errors.INVALID_TOKEN);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid Request");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
}
@@ -230,7 +231,7 @@ public class SamlService {
if (!uriInfo.getAbsolutePath().equals(requestAbstractType.getDestination())) {
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
event.detail(Details.REASON, "invalid_destination");
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid request.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
String bindingType = getBindingType(requestAbstractType);
if ("true".equals(client.getAttribute(SamlProtocol.SAML_FORCE_POST_BINDING))) bindingType = SamlProtocol.SAML_POST_BINDING;
@@ -252,7 +253,7 @@ public class SamlService {
if (redirect == null) {
event.error(Errors.INVALID_REDIRECT_URI);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid redirect_uri.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI );
}
@@ -275,7 +276,7 @@ public class SamlService {
} else {
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
event.detail(Details.REASON, "unsupported_nameid_format");
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unsupported NameIDFormat.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNSUPPORTED_NAME_ID_FORMAT);
}
}
@@ -284,10 +285,10 @@ public class SamlService {
// SPNEGO/Kerberos authentication TODO: This should be somehow pluggable instead of hardcoded this way (Authentication interceptors?)
HttpAuthenticationManager httpAuthManager = new HttpAuthenticationManager(session, clientSession, realm, uriInfo, request, clientConnection, event);
- HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate();
+ HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate(headers);
if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse();
- LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo)
+ LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers)
.setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode());
// Attach state from SPNEGO authentication
@@ -339,7 +340,7 @@ public class SamlService {
if (!uriInfo.getAbsolutePath().equals(logoutRequest.getDestination())) {
event.error(Errors.INVALID_SAML_LOGOUT_REQUEST);
event.detail(Details.REASON, "invalid_destination");
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid request.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REQUEST);
}
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
@@ -366,7 +367,7 @@ public class SamlService {
}
}
logger.debug("browser Logout");
- return authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection);
+ return authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
}
@@ -379,7 +380,7 @@ public class SamlService {
if (redirectUri != null) {
redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
if (redirectUri == null) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid redirect uri.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI );
}
}
if (redirectUri != null) {
@@ -391,7 +392,7 @@ public class SamlService {
}
private Response logout(UserSessionModel userSession) {
- Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection);
+ Response response = authManager.browserLogout(session, realm, userSession, uriInfo, clientConnection, headers);
if (response == null) event.user(userSession.getUser()).session(userSession).success();
return response;
}
diff --git a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
index 7bd4d033c8..0290771d7a 100755
--- a/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -7,6 +7,7 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.provider.Provider;
import org.keycloak.services.managers.ClientSessionCode;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -21,6 +22,8 @@ public interface LoginProtocol extends Provider {
LoginProtocol setUriInfo(UriInfo uriInfo);
+ LoginProtocol setHttpHeaders(HttpHeaders headers);
+
Response cancelLogin(ClientSessionModel clientSession);
Response invalidSessionError(ClientSessionModel clientSession);
Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 3900f1aaf3..433acd7846 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -33,6 +33,7 @@ import org.keycloak.protocol.LoginProtocol;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ResourceAdminManager;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@@ -63,13 +64,17 @@ public class OIDCLoginProtocol implements LoginProtocol {
protected UriInfo uriInfo;
- public OIDCLoginProtocol(KeycloakSession session, RealmModel realm, UriInfo uriInfo) {
+ protected HttpHeaders headers;
+
+ public OIDCLoginProtocol(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
this.session = session;
this.realm = realm;
this.uriInfo = uriInfo;
+ this.headers = headers;
}
- public OIDCLoginProtocol() {
+ public OIDCLoginProtocol(){
+
}
@Override
@@ -90,6 +95,12 @@ public class OIDCLoginProtocol implements LoginProtocol {
return this;
}
+ @Override
+ public OIDCLoginProtocol setHttpHeaders(HttpHeaders headers){
+ this.headers = headers;
+ return this;
+ }
+
@Override
public Response cancelLogin(ClientSessionModel clientSession) {
String redirect = clientSession.getRedirectUri();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index c2ec74bb4b..b4b0de573d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -67,6 +67,9 @@ public class OIDCLoginProtocolService {
@Context
private KeycloakSession session;
+ @Context
+ private HttpHeaders headers;
+
public OIDCLoginProtocolService(RealmModel realm, EventBuilder event, AuthenticationManager authManager) {
this.realm = realm;
this.tokenManager = new TokenManager();
@@ -83,9 +86,19 @@ public class OIDCLoginProtocolService {
return baseUriBuilder.path(RealmsResource.class).path("{realm}/protocol/" + OIDCLoginProtocol.LOGIN_PROTOCOL);
}
- public static UriBuilder accessCodeToTokenUrl(UriBuilder baseUriBuilder) {
+ public static UriBuilder authUrl(UriInfo uriInfo) {
+ UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
+ return authUrl(baseUriBuilder);
+ }
+
+ public static UriBuilder authUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
- return uriBuilder.path(OIDCLoginProtocolService.class, "accessCodeToToken");
+ return uriBuilder.path(OIDCLoginProtocolService.class, "auth");
+ }
+
+ public static UriBuilder tokenUrl(UriBuilder baseUriBuilder) {
+ UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
+ return uriBuilder.path(OIDCLoginProtocolService.class, "token");
}
public static UriBuilder validateAccessTokenUrl(UriBuilder baseUriBuilder) {
@@ -93,21 +106,6 @@ public class OIDCLoginProtocolService {
return uriBuilder.path(OIDCLoginProtocolService.class, "validateAccessToken");
}
- public static UriBuilder grantAccessTokenUrl(UriBuilder baseUriBuilder) {
- UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
- return uriBuilder.path(OIDCLoginProtocolService.class, "grantAccessToken");
- }
-
- public static UriBuilder loginPageUrl(UriInfo uriInfo) {
- UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
- return loginPageUrl(baseUriBuilder);
- }
-
- public static UriBuilder loginPageUrl(UriBuilder baseUriBuilder) {
- UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
- return uriBuilder.path(OIDCLoginProtocolService.class, "loginPage");
- }
-
public static UriBuilder logoutUrl(UriInfo uriInfo) {
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
return logoutUrl(baseUriBuilder);
@@ -118,11 +116,6 @@ public class OIDCLoginProtocolService {
return uriBuilder.path(OIDCLoginProtocolService.class, "logout");
}
- public static UriBuilder refreshUrl(UriBuilder baseUriBuilder) {
- UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
- return uriBuilder.path(OIDCLoginProtocolService.class, "refreshAccessToken");
- }
-
/**
* Authorization endpoint
*/
@@ -226,7 +219,7 @@ public class OIDCLoginProtocolService {
@Path("oauth/oob")
@GET
public Response installedAppUrnCallback(final @QueryParam("code") String code, final @QueryParam("error") String error, final @QueryParam("error_description") String errorDescription) {
- LoginFormsProvider forms = Flows.forms(session, realm, null, uriInfo);
+ LoginFormsProvider forms = Flows.forms(session, realm, null, uriInfo, headers);
if (code != null) {
return forms.setClientSessionCode(code).createCode();
} else {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 07fd828c59..da9fdd83fa 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -30,6 +30,7 @@ import org.keycloak.representations.RefreshToken;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.util.Time;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.util.HashSet;
@@ -73,7 +74,7 @@ public class TokenManager {
}
}
- public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, AccessToken oldToken) throws OAuthErrorException {
+ public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, AccessToken oldToken, HttpHeaders headers) throws OAuthErrorException {
UserModel user = session.users().getUserById(oldToken.getSubject(), realm);
if (user == null) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
@@ -85,7 +86,7 @@ public class TokenManager {
UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
- AuthenticationManager.logout(session, realm, userSession, uriInfo, connection);
+ AuthenticationManager.logout(session, realm, userSession, uriInfo, connection, headers);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
}
ClientSessionModel clientSession = null;
@@ -124,12 +125,12 @@ public class TokenManager {
}
- public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
+ public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event, HttpHeaders headers) throws OAuthErrorException {
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
- TokenValidation validation = validateToken(session, uriInfo, connection, realm, refreshToken);
+ TokenValidation validation = validateToken(session, uriInfo, connection, realm, refreshToken, headers);
// validate authorizedClient is same as validated client
if (!validation.clientSession.getClient().getId().equals(authorizedClient.getId())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token. Token client and authorized client don't match");
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 6f6441f55e..bebf70341c 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -24,6 +24,7 @@ import org.keycloak.services.ErrorPageException;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.HttpAuthenticationManager;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.Urls;
@@ -105,8 +106,7 @@ public class AuthorizationEndpoint {
* @deprecated
*/
public AuthorizationEndpoint legacy(String legacyResponseType) {
- // TODO Change to warn once adapters has been updated
- logger.debugv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
+ logger.warnv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
this.legacyResponseType = legacyResponseType;
return this;
}
@@ -116,7 +116,7 @@ public class AuthorizationEndpoint {
action = Action.REGISTER;
if (!realm.isRegistrationAllowed()) {
- throw new ErrorPageException(session, realm, uriInfo, "Registration not allowed");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED);
}
return this;
@@ -148,21 +148,21 @@ public class AuthorizationEndpoint {
private void checkSsl() {
if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
event.error(Errors.SSL_REQUIRED);
- throw new ErrorPageException(session, realm, uriInfo, "HTTPS required");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
}
}
private void checkRealm() {
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- throw new ErrorPageException(session, realm, uriInfo, "Realm not enabled");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
}
private void checkClient() {
if (clientId == null) {
event.error(Errors.INVALID_REQUEST);
- throw new ErrorPageException(session, realm, uriInfo, "Missing paramater: " + OIDCLoginProtocol.CLIENT_ID_PARAM);
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.MISSING_PARAMETER, OIDCLoginProtocol.CLIENT_ID_PARAM );
}
event.client(clientId);
@@ -170,17 +170,17 @@ public class AuthorizationEndpoint {
client = realm.findClient(clientId);
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
- throw new ErrorPageException(session, realm, uriInfo, "Client not found");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.CLIENT_NOT_FOUND );
}
if ((client instanceof ApplicationModel) && ((ApplicationModel) client).isBearerOnly()) {
event.error(Errors.NOT_ALLOWED);
- throw new ErrorPageException(session, realm, uriInfo, "Bearer only clients are not allowed to initiate browser login");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.BEARER_ONLY );
}
if (client.isDirectGrantsOnly()) {
event.error(Errors.NOT_ALLOWED);
- throw new ErrorPageException(session, realm, uriInfo, "Direct grants only clients are not allowed to initiate browser login");
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.DIRECT_GRANTS_ONLY);
}
}
@@ -190,7 +190,7 @@ public class AuthorizationEndpoint {
responseType = legacyResponseType;
} else {
event.error(Errors.INVALID_REQUEST);
- throw new ErrorPageException(session, realm, uriInfo, "Missing query parameter: " + OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM );
}
}
@@ -200,7 +200,7 @@ public class AuthorizationEndpoint {
action = Action.CODE;
} else {
event.error(Errors.INVALID_REQUEST);
- throw new ErrorPageException(session, realm, uriInfo, "Invalid " + OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM );
}
}
@@ -210,7 +210,7 @@ public class AuthorizationEndpoint {
redirectUri = RedirectUtils.verifyRedirectUri(uriInfo, redirectUriParam, realm, client);
if (redirectUri == null) {
event.error(Errors.INVALID_REDIRECT_URI);
- throw new ErrorPageException(session, realm, uriInfo, "Invalid " + OIDCLoginProtocol.REDIRECT_URI_PARAM);
+ throw new ErrorPageException(session, realm, uriInfo, headers, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM);
}
}
@@ -237,8 +237,8 @@ public class AuthorizationEndpoint {
IdentityProviderModel identityProviderModel = realm.getIdentityProviderById(idpHint);
if (identityProviderModel == null) {
- return Flows.forms(session, realm, null, uriInfo)
- .setError("Could not find an identity provider with the identifier [" + idpHint + "].")
+ return Flows.forms(session, realm, null, uriInfo, headers)
+ .setError(Messages.IDENTITY_PROVIDER_NOT_FOUND, idpHint)
.createErrorPage();
}
return buildRedirectToIdentityProvider(idpHint, accessCode);
@@ -249,11 +249,11 @@ public class AuthorizationEndpoint {
// SPNEGO/Kerberos authentication TODO: This should be somehow pluggable instead of hardcoded this way (Authentication interceptors?)
HttpAuthenticationManager httpAuthManager = new HttpAuthenticationManager(session, clientSession, realm, uriInfo, request, clientConnection, event);
- HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate();
+ HttpAuthenticationManager.HttpAuthOutput httpAuthOutput = httpAuthManager.spnegoAuthenticate(headers);
if (httpAuthOutput.getResponse() != null) return httpAuthOutput.getResponse();
if (prompt != null && prompt.equals("none")) {
- OIDCLoginProtocol oauth = new OIDCLoginProtocol(session, realm, uriInfo);
+ OIDCLoginProtocol oauth = new OIDCLoginProtocol(session, realm, uriInfo, headers);
return oauth.cancelLogin(clientSession);
}
@@ -271,13 +271,13 @@ public class AuthorizationEndpoint {
return buildRedirectToIdentityProvider(identityProviders.get(0).getId(), accessCode);
}
- return Flows.forms(session, realm, null, uriInfo).setError("Realm [" + realm.getName() + "] supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.").createErrorPage();
+ return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.IDENTITY_PROVIDER_NOT_UNIQUE, realm.getName()).createErrorPage();
}
- return Flows.forms(session, realm, null, uriInfo).setError("Realm [" + realm.getName() + "] does not support any credential type.").createErrorPage();
+ return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.REALM_SUPPORTS_NO_CREDENTIALS, realm.getName()).createErrorPage();
}
- LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo)
+ LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers)
.setClientSessionCode(accessCode);
// Attach state from SPNEGO authentication
@@ -306,7 +306,7 @@ public class AuthorizationEndpoint {
private Response buildRegister() {
authManager.expireIdentityCookie(realm, uriInfo, clientConnection);
- return Flows.forms(session, realm, client, uriInfo)
+ return Flows.forms(session, realm, client, uriInfo, headers)
.setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode())
.createRegistration();
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
index 16ab80c043..a47aa6a2c1 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -21,6 +21,7 @@ import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.representations.RefreshToken;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.flows.Flows;
@@ -91,7 +92,7 @@ public class LogoutEndpoint {
if (redirectUri != null) {
String validatedRedirect = RedirectUtils.verifyRealmRedirectUri(uriInfo, redirectUri, realm);
if (validatedRedirect == null) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid redirect uri.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_REDIRECT_URI);
}
return Response.status(302).location(UriBuilder.fromUri(validatedRedirect).build()).build();
} else {
@@ -143,7 +144,7 @@ public class LogoutEndpoint {
}
private void logout(UserSessionModel userSession) {
- authManager.logout(session, realm, userSession, uriInfo, clientConnection);
+ authManager.logout(session, realm, userSession, uriInfo, clientConnection, headers);
event.user(userSession.getUser()).session(userSession).success();
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index ab78e6c7a9..d8f9db2815 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -47,6 +47,8 @@ import java.util.Map;
public class TokenEndpoint {
private static final Logger logger = Logger.getLogger(TokenEndpoint.class);
+ private MultivaluedMap formParams;
+ private ClientModel client;
private enum Action {
AUTHORIZATION_CODE, REFRESH_TOKEN, PASSWORD
@@ -74,10 +76,7 @@ public class TokenEndpoint {
private Action action;
- private String clientId;
private String grantType;
- private String code;
- private String redirectUri;
private String legacyGrantType;
@@ -89,15 +88,14 @@ public class TokenEndpoint {
}
@POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- public Response build(final MultivaluedMap formData) {
+ public Response build() {
switch (action) {
case AUTHORIZATION_CODE:
- return buildAuthorizationCodeAccessTokenResponse(formData);
+ return buildAuthorizationCodeAccessTokenResponse();
case REFRESH_TOKEN:
- return buildRefreshToken(formData);
+ return buildRefreshToken();
case PASSWORD:
- return buildResourceOwnerPasswordCredentialsGrant(formData);
+ return buildResourceOwnerPasswordCredentialsGrant();
}
throw new RuntimeException("Unknown action " + action);
@@ -115,23 +113,19 @@ public class TokenEndpoint {
* @deprecated
*/
public TokenEndpoint legacy(String legacyGrantType) {
- // TODO Change to warn once adapters has been updated
- logger.debugv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
+ logger.warnv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
this.legacyGrantType = legacyGrantType;
return this;
}
public TokenEndpoint init() {
- MultivaluedMap params = uriInfo.getQueryParameters();
-
- clientId = params.getFirst(OIDCLoginProtocol.CLIENT_ID_PARAM);
- grantType = params.getFirst(OIDCLoginProtocol.GRANT_TYPE_PARAM);
- code = params.getFirst(OIDCLoginProtocol.CODE_PARAM);
- redirectUri = params.getFirst(OIDCLoginProtocol.REDIRECT_URI_PARAM);
+ formParams = request.getDecodedFormParameters();
+ grantType = formParams.getFirst(OIDCLoginProtocol.GRANT_TYPE_PARAM);
checkSsl();
checkRealm();
checkGrantType();
+ checkClient();
return this;
}
@@ -148,15 +142,13 @@ public class TokenEndpoint {
}
}
- private ClientModel authorizeClient(final MultivaluedMap formData) {
+ private void checkClient() {
String authorizationHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
- ClientModel client = AuthorizeClientUtil.authorizeClient(authorizationHeader, formData, event, realm);
+ client = AuthorizeClientUtil.authorizeClient(authorizationHeader, formParams, event, realm);
if ((client instanceof ApplicationModel) && ((ApplicationModel) client).isBearerOnly()) {
throw new ErrorResponseException("invalid_client", "Bearer-only not allowed", Response.Status.BAD_REQUEST);
}
-
- return client;
}
private void checkGrantType() {
@@ -182,8 +174,8 @@ public class TokenEndpoint {
}
}
- public Response buildAuthorizationCodeAccessTokenResponse(final MultivaluedMap formData) {
- String code = formData.getFirst(OAuth2Constants.CODE);
+ public Response buildAuthorizationCodeAccessTokenResponse() {
+ String code = formParams.getFirst(OAuth2Constants.CODE);
if (code == null) {
event.error(Errors.INVALID_CODE);
throw new ErrorResponseException("invalid_request", "Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
@@ -214,10 +206,8 @@ public class TokenEndpoint {
event.user(userSession.getUser());
event.session(userSession.getId());
- ClientModel client = authorizeClient(formData);
-
String redirectUri = clientSession.getNote(OIDCLoginProtocol.REDIRECT_URI_PARAM);
- if (redirectUri != null && !redirectUri.equals(formData.getFirst(OAuth2Constants.REDIRECT_URI))) {
+ if (redirectUri != null && !redirectUri.equals(formParams.getFirst(OAuth2Constants.REDIRECT_URI))) {
event.error(Errors.INVALID_CODE);
throw new ErrorResponseException("invalid_grant", "Incorrect redirect_uri", Response.Status.BAD_REQUEST);
}
@@ -243,9 +233,9 @@ public class TokenEndpoint {
throw new ErrorResponseException("invalid_grant", "Session not active", Response.Status.BAD_REQUEST);
}
- String adapterSessionId = formData.getFirst(AdapterConstants.APPLICATION_SESSION_STATE);
+ String adapterSessionId = formParams.getFirst(AdapterConstants.APPLICATION_SESSION_STATE);
if (adapterSessionId != null) {
- String adapterSessionHost = formData.getFirst(AdapterConstants.APPLICATION_SESSION_HOST);
+ String adapterSessionHost = formParams.getFirst(AdapterConstants.APPLICATION_SESSION_HOST);
logger.debugf("Adapter Session '%s' saved in ClientSession for client '%s'. Host is '%s'", adapterSessionId, client.getClientId(), adapterSessionHost);
event.detail(AdapterConstants.APPLICATION_SESSION_STATE, adapterSessionId);
@@ -266,17 +256,15 @@ public class TokenEndpoint {
return Cors.add(request, Response.ok(res).type(MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
- public Response buildRefreshToken(final MultivaluedMap formData) {
- ClientModel client = authorizeClient(formData);
-
- String refreshToken = formData.getFirst(OAuth2Constants.REFRESH_TOKEN);
+ public Response buildRefreshToken() {
+ String refreshToken = formParams.getFirst(OAuth2Constants.REFRESH_TOKEN);
if (refreshToken == null) {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "No refresh token", Response.Status.BAD_REQUEST);
}
AccessTokenResponse res;
try {
- res = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event);
+ res = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event, headers);
} catch (OAuthErrorException e) {
event.error(Errors.INVALID_TOKEN);
throw new ErrorResponseException(e.getError(), e.getDescription(), Response.Status.BAD_REQUEST);
@@ -287,14 +275,14 @@ public class TokenEndpoint {
return Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
- public Response buildResourceOwnerPasswordCredentialsGrant(final MultivaluedMap formData) {
+ public Response buildResourceOwnerPasswordCredentialsGrant() {
if (!realm.isPasswordCredentialGrantAllowed()) {
throw new ErrorResponseException("not_enabled", "Direct Grant REST API not enabled", Response.Status.FORBIDDEN);
}
event.detail(Details.AUTH_METHOD, "oauth_credentials").detail(Details.RESPONSE_TYPE, "token");
- String username = formData.getFirst(AuthenticationManager.FORM_USERNAME);
+ String username = formParams.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
event.error(Errors.USERNAME_MISSING);
throw new ErrorResponseException("invalid_request", "Missing parameter: username", Response.Status.UNAUTHORIZED);
@@ -304,9 +292,7 @@ public class TokenEndpoint {
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username);
if (user != null) event.user(user);
- ClientModel client = authorizeClient(formData);
-
- AuthenticationManager.AuthenticationStatus authenticationStatus = authManager.authenticateForm(session, clientConnection, realm, formData);
+ AuthenticationManager.AuthenticationStatus authenticationStatus = authManager.authenticateForm(session, clientConnection, realm, formParams);
Map err;
switch (authenticationStatus) {
@@ -324,7 +310,7 @@ public class TokenEndpoint {
throw new ErrorResponseException("invalid_grant", "Invalid user credentials", Response.Status.UNAUTHORIZED);
}
- String scope = formData.getFirst(OAuth2Constants.SCOPE);
+ String scope = formParams.getFirst(OAuth2Constants.SCOPE);
UserSessionProvider sessions = session.sessions();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java
index caef4361e0..8dad6fd490 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/ValidateTokenEndpoint.java
@@ -20,10 +20,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.*;
import java.util.HashMap;
import java.util.Map;
@@ -43,6 +40,9 @@ public class ValidateTokenEndpoint {
@Context
private UriInfo uriInfo;
+ @Context
+ private HttpHeaders headers;
+
private TokenManager tokenManager;
private RealmModel realm;
private EventBuilder event;
@@ -81,7 +81,7 @@ public class ValidateTokenEndpoint {
event.user(token.getSubject()).session(token.getSessionState()).detail(Details.VALIDATE_ACCESS_TOKEN, token.getId());
try {
- tokenManager.validateToken(session, uriInfo, clientConnection, realm, token);
+ tokenManager.validateToken(session, uriInfo, clientConnection, realm, token, headers);
} catch (OAuthErrorException e) {
Map error = new HashMap();
error.put(OAuth2Constants.ERROR, e.getError());
diff --git a/services/src/main/java/org/keycloak/services/ErrorPageException.java b/services/src/main/java/org/keycloak/services/ErrorPageException.java
index 3f8d435ff0..634ea7a7ac 100644
--- a/services/src/main/java/org/keycloak/services/ErrorPageException.java
+++ b/services/src/main/java/org/keycloak/services/ErrorPageException.java
@@ -5,6 +5,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.services.resources.flows.Flows;
import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -16,18 +17,22 @@ public class ErrorPageException extends WebApplicationException {
private final KeycloakSession session;
private final RealmModel realm;
private final UriInfo uriInfo;
+ private final HttpHeaders httpHeaders;
private final String errorMessage;
+ private final Object[] parameters;
- public ErrorPageException(KeycloakSession session, RealmModel realm, UriInfo uriInfo, String errorMessage) {
+ public ErrorPageException(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String errorMessage, Object ... parameters) {
this.session = session;
this.realm = realm;
this.uriInfo = uriInfo;
+ this.httpHeaders = headers;
this.errorMessage = errorMessage;
+ this.parameters = parameters;
}
@Override
public Response getResponse() {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, errorMessage);
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, httpHeaders, errorMessage, parameters);
}
}
diff --git a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
index e3bb56971a..9e0e4ab161 100755
--- a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java
@@ -42,7 +42,7 @@ public class AppAuthManager extends AuthenticationManager {
public AuthResult authenticateBearerToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
String tokenString = extractAuthorizationHeaderToken(headers);
if (tokenString == null) return null;
- AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, true, tokenString);
+ AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, true, tokenString, headers);
return authResult;
}
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index aa27f17a94..f37b83781d 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -79,7 +79,7 @@ public class AuthenticationManager {
return userSession != null && userSession.getLastSessionRefresh() + realm.getSsoSessionIdleTimeout() > currentTime && max > currentTime;
}
- public static void logout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection) {
+ public static void logout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
if (userSession == null) return;
UserModel user = userSession.getUser();
userSession.setState(UserSessionModel.State.LOGGING_OUT);
@@ -95,6 +95,7 @@ public class AuthenticationManager {
if (authMethod == null) continue; // must be a keycloak service like account
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
protocol.backchannelLogout(userSession, clientSession);
clientSession.setAction(ClientSessionModel.Action.LOGGED_OUT);
@@ -105,7 +106,7 @@ public class AuthenticationManager {
}
- public static Response browserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection) {
+ public static Response browserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
if (userSession == null) return null;
UserModel user = userSession.getUser();
@@ -128,6 +129,7 @@ public class AuthenticationManager {
if (authMethod == null) continue; // must be a keycloak service like account
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
try {
logger.debugv("backchannel logout to: {0}", client.getClientId());
@@ -140,12 +142,13 @@ public class AuthenticationManager {
}
if (redirectClients.size() == 0) {
- return finishBrowserLogout(session, realm, userSession, uriInfo, connection);
+ return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
}
for (ClientSessionModel nextRedirectClient : redirectClients) {
String authMethod = nextRedirectClient.getAuthMethod();
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
// setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not
nextRedirectClient.setAction(ClientSessionModel.Action.LOGGED_OUT);
@@ -161,16 +164,17 @@ public class AuthenticationManager {
}
}
- return finishBrowserLogout(session, realm, userSession, uriInfo, connection);
+ return finishBrowserLogout(session, realm, userSession, uriInfo, connection, headers);
}
- protected static Response finishBrowserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection) {
+ protected static Response finishBrowserLogout(KeycloakSession session, RealmModel realm, UserSessionModel userSession, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers) {
expireIdentityCookie(realm, uriInfo, connection);
expireRememberMeCookie(realm, uriInfo, connection);
userSession.setState(UserSessionModel.State.LOGGED_OUT);
String method = userSession.getNote(KEYCLOAK_LOGOUT_PROTOCOL);
LoginProtocol protocol = session.getProvider(LoginProtocol.class, method);
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
Response response = protocol.finishLogout(userSession);
session.sessions().removeUserSession(realm, userSession);
@@ -285,7 +289,7 @@ public class AuthenticationManager {
}
String tokenString = cookie.getValue();
- AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, checkActive, tokenString);
+ AuthResult authResult = verifyIdentityToken(session, realm, uriInfo, connection, checkActive, tokenString, headers);
if (authResult == null) {
expireIdentityCookie(realm, uriInfo, connection);
return null;
@@ -335,6 +339,7 @@ public class AuthenticationManager {
if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
protocol.setRealm(realm)
+ .setHttpHeaders(request.getHttpHeaders())
.setUriInfo(uriInfo);
return protocol.authenticated(userSession, new ClientSessionCode(realm, clientSession));
@@ -364,7 +369,7 @@ public class AuthenticationManager {
UserModel.RequiredAction action = user.getRequiredActions().iterator().next();
accessCode.setRequiredAction(action);
- LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo).setClientSessionCode(accessCode.getCode()).setUser(user);
+ LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders()).setClientSessionCode(accessCode.getCode()).setUser(user);
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) {
event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success();
LoginActionsService.createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
@@ -387,7 +392,7 @@ public class AuthenticationManager {
}
}
- return Flows.forms(session, realm, client, uriInfo)
+ return Flows.forms(session, realm, client, uriInfo, request.getHttpHeaders())
.setClientSessionCode(accessCode.getCode())
.setAccessRequest(realmRoles, resourceRoles)
.setClient(client)
@@ -415,7 +420,7 @@ public class AuthenticationManager {
}
}
- protected AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString) {
+ protected AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) {
try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName(), checkActive);
if (checkActive) {
@@ -435,7 +440,7 @@ public class AuthenticationManager {
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
if (!isSessionValid(realm, userSession)) {
- if (userSession != null) logout(session, realm, userSession, uriInfo, connection);
+ if (userSession != null) logout(session, realm, userSession, uriInfo, connection, headers);
logger.debug("User session not active");
return null;
}
diff --git a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
index 7dca9c1482..702b684aba 100644
--- a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
@@ -58,7 +58,7 @@ public class HttpAuthenticationManager {
}
- public HttpAuthOutput spnegoAuthenticate() {
+ public HttpAuthOutput spnegoAuthenticate(HttpHeaders headers) {
boolean kerberosSupported = false;
for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
if (c.getType().equals(CredentialRepresentation.KERBEROS)) {
@@ -96,7 +96,7 @@ public class HttpAuthenticationManager {
CredentialValidationOutput output = session.users().validCredentials(realm, spnegoCredential);
if (output.getAuthStatus() == CredentialValidationOutput.Status.AUTHENTICATED) {
- return sendResponse(output.getAuthenticatedUser(), output.getState(), "spnego");
+ return sendResponse(output.getAuthenticatedUser(), output.getState(), "spnego", headers);
} else {
String spnegoResponseToken = (String) output.getState().get(KerberosConstants.RESPONSE_TOKEN);
return challengeNegotiation(spnegoResponseToken);
@@ -106,7 +106,7 @@ public class HttpAuthenticationManager {
// Send response after successful authentication
- private HttpAuthOutput sendResponse(UserModel user, Map authState, String authMethod) {
+ private HttpAuthOutput sendResponse(UserModel user, Map authState, String authMethod, HttpHeaders headers) {
if (logger.isTraceEnabled()) {
logger.trace("User " + user.getUsername() + " authenticated with " + authMethod);
}
@@ -114,7 +114,7 @@ public class HttpAuthenticationManager {
Response response;
if (!user.isEnabled()) {
event.error(Errors.USER_DISABLED);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, Messages.ACCOUNT_DISABLED);
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.ACCOUNT_DISABLED);
} else {
UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), authMethod, false);
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index 0ad03522f8..a1cc072e9b 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -26,67 +26,151 @@ package org.keycloak.services.messages;
*/
public class Messages {
- public static final String ACCOUNT_DISABLED = "accountDisabled";
- public static final String ACCOUNT_TEMPORARILY_DISABLED = "accountTemporarilyDisabled";
+ public static final String INVALID_USER = "invalidUserMessage";
- public static final String INVALID_PASSWORD = "invalidPassword";
+ public static final String INVALID_EMAIL = "invalidEmailMessage";
- public static final String INVALID_PASSWORD_EXISTING = "invalidPasswordExisting";
+ public static final String ACCOUNT_DISABLED = "accountDisabledMessage";
- public static final String INVALID_PASSWORD_CONFIRM = "invalidPasswordConfirm";
+ public static final String ACCOUNT_TEMPORARILY_DISABLED = "accountTemporarilyDisabledMessage";
- public static final String INVALID_EMAIL = "invalidEmail";
+ public static final String EXPIRED_CODE = "expiredCodeMessage";
- public static final String INVALID_USER = "invalidUser";
+ public static final String MISSING_FIRST_NAME = "missingFirstNameMessage";
- public static final String EXPIRED_CODE = "expiredCode";
+ public static final String MISSING_LAST_NAME = "missingLastNameMessage";
- public static final String READ_ONLY_USER = "readOnlyUser";
+ public static final String MISSING_EMAIL = "missingEmailMessage";
- public static final String READ_ONLY_PASSWORD = "readOnlyPassword";
+ public static final String MISSING_USERNAME = "missingUsernameMessage";
- public static final String MISSING_EMAIL = "missingEmail";
+ public static final String MISSING_PASSWORD = "missingPasswordMessage";
- public static final String MISSING_FIRST_NAME = "missingFirstName";
+ public static final String MISSING_TOTP = "missingTotpMessage";
- public static final String MISSING_LAST_NAME = "missingLastName";
+ public static final String NOTMATCH_PASSWORD = "notMatchPasswordMessage";
- public static final String MISSING_PASSWORD = "missingPassword";
+ public static final String INVALID_PASSWORD_EXISTING = "invalidPasswordExistingMessage";
- public static final String NOTMATCH_PASSWORD = "notMatchPassword";
+ public static final String INVALID_PASSWORD_CONFIRM = "invalidPasswordConfirmMessage";
- public static final String MISSING_USERNAME = "missingUsername";
+ public static final String INVALID_TOTP = "invalidTotpMessage";
- public static final String MISSING_TOTP = "missingTotp";
+ public static final String USERNAME_EXISTS = "usernameExistsMessage";
- public static final String INVALID_TOTP = "invalidTotp";
+ public static final String EMAIL_EXISTS = "emailExistsMessage";
- public static final String USERNAME_EXISTS = "usernameExists";
+ public static final String FEDERATED_IDENTITY_EMAIL_EXISTS = "federatedIdentityEmailExistsMessage";
- public static final String EMAIL_EXISTS = "emailExists";
+ public static final String FEDERATED_IDENTITY_USERNAME_EXISTS = "federatedIdentityUsernameExistsMessage";
- public static final String ACTION_WARN_TOTP = "actionTotpWarning";
+ public static final String CONFIGURE_TOTP = "configureTotpMessage";
- public static final String ACTION_WARN_PROFILE = "actionProfileWarning";
+ public static final String UPDATE_PROFILE = "updateProfileMessage";
- public static final String ACTION_WARN_PASSWD = "actionPasswordWarning";
+ public static final String UPDATE_PASSWORD = "updatePasswordMessage";
- public static final String ACTION_WARN_EMAIL = "actionEmailWarning";
+ public static final String VERIFY_EMAIL = "verifyEmailMessage";
- public static final String MISSING_IDENTITY_PROVIDER = "missingIdentityProvider";
+ public static final String EMAIL_VERIFIED = "emailVerifiedMessage";
- public static final String INVALID_FEDERATED_IDENTITY_ACTION = "invalidFederatedIdentityAction";
+ public static final String EMAIL_SENT = "emailSentMessage";
- public static final String IDENTITY_PROVIDER_NOT_FOUND = "identityProviderNotFound";
+ public static final String EMAIL_SENT_ERROR = "emailSendErrorMessage";
- public static final String FEDERATED_IDENTITY_NOT_ACTIVE = "federatedIdentityLinkNotActive";
+ public static final String ACCOUNT_UPDATED = "accountUpdatedMessage";
- public static final String FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER = "federatedIdentityRemovingLastProvider";
+ public static final String ACCOUNT_PASSWORD_UPDATED = "accountPasswordUpdatedMessage";
- public static final String IDENTITY_PROVIDER_REDIRECT_ERROR = "identityProviderRedirectError";
+ public static final String NO_ACCESS = "noAccessMessage";
- public static final String IDENTITY_PROVIDER_REMOVED = "identityProviderRemoved";
+ public static final String FAILED_TO_PROCESS_RESPONSE = "failedToProcessResponseMessage";
- public static final String ERROR = "error";
+ public static final String HTTPS_REQUIRED = "httpsRequiredMessage";
+ public static final String REALM_NOT_ENABLED = "realmNotEnabledMessage";
+
+ public static final String INVALID_REQUEST = "invalidRequestMessage";
+
+ public static final String INVALID_REQUESTER = "invalidRequesterMessage";
+
+ public static final String UNKNOWN_LOGIN_REQUESTER = "unknownLoginRequesterMessage";
+
+ public static final String LOGIN_REQUESTER_NOT_ENABLED = "loginRequesterNotEnabledMessage";
+
+ public static final String BEARER_ONLY = "bearerOnlyMessage";
+
+ public static final String DIRECT_GRANTS_ONLY = "directGrantsOnlyMessage";
+
+ public static final String INVALID_REDIRECT_URI = "invalidRedirectUriMessage";
+
+ public static final String UNSUPPORTED_NAME_ID_FORMAT = "unsupportedNameIdFormatMessage";
+
+ public static final String REGISTRATION_NOT_ALLOWED = "registrationNotAllowedMessage";
+
+ public static final String PERMISSION_NOT_APPROVED = "permissionNotApprovedMessage";
+
+ public static final String NO_RELAY_STATE_IN_RESPONSE = "noRelayStateInResponseMessage";
+
+ public static final String IDENTITY_PROVIDER_ALREADY_LINKED = "identityProviderAlreadyLinkedMessage";
+
+ public static final String INSUFFICIENT_PERMISSION = "insufficientPermissionMessage";
+
+ public static final String COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST = "couldNotProceedWithAuthenticationRequestMessage";
+
+ public static final String COULD_NOT_OBTAIN_TOKEN = "couldNotObtainTokenMessage";
+
+ public static final String UNEXPECTED_ERROR_RETRIEVING_TOKEN = "unexpectedErrorRetrievingTokenMessage";
+
+ public static final String IDENTITY_PROVIDER_AUTHENTICATION_FAILED = "identityProviderAuthenticationFailedMessage";
+
+ public static final String UNEXPECTED_ERROR_HANDLING_RESPONSE = "unexpectedErrorHandlingResponseMessage";
+
+ public static final String COULD_NOT_SEND_AUTHENTICATION_REQUEST = "couldNotSendAuthenticationRequestMessage";
+
+ public static final String UNEXPECTED_ERROR_HANDLING_REQUEST = "unexpectedErrorHandlingRequestMessage";
+
+ public static final String INVALID_ACCESS_CODE = "invalidAccessCodeMessage";
+
+ public static final String SESSION_NOT_ACTIVE = "sessionNotActiveMessage";
+
+ public static final String UNKNOWN_CODE = "unknownCodeMessage";
+
+ public static final String INVALID_CODE = "invalidCodeMessage";
+
+ public static final String IDENTITY_PROVIDER_UNEXPECTED_ERROR = "identityProviderUnexpectedErrorMessage";
+
+ public static final String IDENTITY_PROVIDER_NOT_FOUND = "identityProviderNotFoundMessage";
+
+ public static final String IDENTITY_PROVIDER_NOT_UNIQUE = "identityProviderNotUniqueMessage";
+
+ public static final String REALM_SUPPORTS_NO_CREDENTIALS = "realmSupportsNoCredentialsMessage";
+
+ public static final String READ_ONLY_USER = "readOnlyUserMessage";
+
+ public static final String READ_ONLY_PASSWORD = "readOnlyPasswordMessage";
+
+ public static final String SUCCESS_TOTP_REMOVED = "successTotpRemovedMessage";
+
+ public static final String SUCCESS_TOTP = "successTotpMessage";
+
+ public static final String MISSING_IDENTITY_PROVIDER = "missingIdentityProviderMessage";
+
+ public static final String INVALID_FEDERATED_IDENTITY_ACTION = "invalidFederatedIdentityActionMessage";
+
+ public static final String FEDERATED_IDENTITY_NOT_ACTIVE = "federatedIdentityLinkNotActiveMessage";
+
+ public static final String FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER = "federatedIdentityRemovingLastProviderMessage";
+
+ public static final String IDENTITY_PROVIDER_REDIRECT_ERROR = "identityProviderRedirectErrorMessage";
+
+ public static final String IDENTITY_PROVIDER_REMOVED = "identityProviderRemovedMessage";
+
+ public static final String MISSING_PARAMETER = "missingParameterMessage";
+
+ public static final String CLIENT_NOT_FOUND = "clientNotFoundMessage";
+
+ public static final String INVALID_PARAMETER = "invalidParameterMessage";
+
+ public static final String FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING = "federatedIdentityRegistrationEmailMissingMessage";
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 8b5297b298..fae89525c7 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -25,6 +25,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
+import org.keycloak.OAuth2Constants;
import org.keycloak.account.AccountPages;
import org.keycloak.account.AccountProvider;
import org.keycloak.events.Details;
@@ -32,20 +33,7 @@ import org.keycloak.events.Event;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventStoreProvider;
import org.keycloak.events.EventType;
-import org.keycloak.models.AccountRoles;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.FederatedIdentityModel;
-import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.ModelReadOnlyException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserCredentialValueModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.*;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -160,7 +148,7 @@ public class AccountService {
public void init() {
eventStore = session.getProvider(EventStoreProvider.class);
- account = session.getProvider(AccountProvider.class).setRealm(realm).setUriInfo(uriInfo);
+ account = session.getProvider(AccountProvider.class).setRealm(realm).setUriInfo(uriInfo).setHttpHeaders(headers);
AuthenticationManager.AuthResult authResult = authManager.authenticateBearerToken(session, realm, uriInfo, clientConnection, headers);
if (authResult != null) {
@@ -242,7 +230,7 @@ public class AccountService {
try {
require(AccountRoles.MANAGE_ACCOUNT);
} catch (ForbiddenException e) {
- return Flows.forms(session, realm, null, uriInfo).setError("No access").createErrorPage();
+ return Flows.forms(session, realm, null, uriInfo, headers).setError(Messages.NO_ACCESS).createErrorPage();
}
setReferrerOnPage();
@@ -442,7 +430,7 @@ public class AccountService {
event.clone().event(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, oldEmail).detail(Details.UPDATED_EMAIL, email).success();
}
setReferrerOnPage();
- return account.setSuccess("accountUpdated").createResponse(AccountPages.ACCOUNT);
+ return account.setSuccess(Messages.ACCOUNT_UPDATED).createResponse(AccountPages.ACCOUNT);
} catch (ModelReadOnlyException roe) {
setReferrerOnPage();
return account.setError(Messages.READ_ONLY_USER).setProfileFormData(formData).createResponse(AccountPages.ACCOUNT);
@@ -466,7 +454,7 @@ public class AccountService {
event.event(EventType.REMOVE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
- return account.setSuccess("successTotpRemoved").createResponse(AccountPages.TOTP);
+ return account.setSuccess(Messages.SUCCESS_TOTP_REMOVED).createResponse(AccountPages.TOTP);
}
@@ -545,7 +533,7 @@ public class AccountService {
event.event(EventType.UPDATE_TOTP).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
- return account.setSuccess("successTotp").createResponse(AccountPages.TOTP);
+ return account.setSuccess(Messages.SUCCESS_TOTP).createResponse(AccountPages.TOTP);
}
/**
@@ -614,7 +602,11 @@ public class AccountService {
} catch (ModelReadOnlyException mre) {
setReferrerOnPage();
return account.setError(Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD);
- } catch (Exception ape) {
+ }catch (ModelException me) {
+ logger.error("Failed to update password", me);
+ setReferrerOnPage();
+ return account.setError(me.getMessage(), me.getParameters()).createResponse(AccountPages.PASSWORD);
+ }catch (Exception ape) {
logger.error("Failed to update password", ape);
setReferrerOnPage();
return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
@@ -631,7 +623,7 @@ public class AccountService {
event.event(EventType.UPDATE_PASSWORD).client(auth.getClient()).user(auth.getUser()).success();
setReferrerOnPage();
- return account.setPasswordSet(true).setSuccess("accountPasswordUpdated").createResponse(AccountPages.PASSWORD);
+ return account.setPasswordSet(true).setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED).createResponse(AccountPages.PASSWORD);
}
@Path("federated-identity-update")
@@ -772,7 +764,7 @@ public class AccountService {
private Response login(String path) {
OAuthRedirect oauth = new OAuthRedirect();
- String authUrl = OIDCLoginProtocolService.loginPageUrl(uriInfo).build(realm.getName()).toString();
+ String authUrl = OIDCLoginProtocolService.authUrl(uriInfo).build(realm.getName()).toString();
oauth.setAuthUrl(authUrl);
oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_APP);
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 0bf652b9a3..a0ea1cba1a 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -46,6 +46,7 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.social.SocialIdentityProvider;
@@ -57,13 +58,8 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
+import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -97,6 +93,10 @@ public class IdentityBrokerService {
@Context
private HttpRequest request;
+
+ @Context
+ private HttpHeaders headers;
+
private EventBuilder event;
public IdentityBrokerService(RealmModel realmModel) {
@@ -135,12 +135,12 @@ public class IdentityBrokerService {
return response;
}
} catch (IdentityBrokerException e) {
- return redirectToErrorPage("Could not send authentication request to identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.COULD_NOT_SEND_AUTHENTICATION_REQUEST, e, providerId);
} catch (Exception e) {
- return redirectToErrorPage("Unexpected error when handling authentication request to identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.UNEXPECTED_ERROR_HANDLING_REQUEST, e, providerId);
}
- return redirectToErrorPage("Could not proceed with authentication request to identity provider.");
+ return redirectToErrorPage(Messages.COULD_NOT_PROCEED_WITH_AUTHENTICATION_REQUEST);
}
@GET
@@ -202,11 +202,10 @@ public class IdentityBrokerService {
}
if (OAuthClientModel.class.isInstance(clientModel) && !forceRetrieval) {
- return corsResponse(Flows.forms(this.session, this.realmModel, clientModel, this.uriInfo)
+ return corsResponse(Flows.forms(this.session, this.realmModel, clientModel, this.uriInfo, headers)
.setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders()))
.setAccessRequest("Your information from " + providerId + " identity provider.")
.setClient(clientModel)
- .setUriInfo(this.uriInfo)
.setActionUri(this.uriInfo.getRequestUri())
.createOAuthGrant(null), clientModel);
}
@@ -231,9 +230,9 @@ public class IdentityBrokerService {
return badRequest("Invalid token.");
} catch (IdentityBrokerException e) {
- return redirectToErrorPage("Could not obtain token fron identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.COULD_NOT_OBTAIN_TOKEN, e, providerId);
} catch (Exception e) {
- return redirectToErrorPage("Unexpected error when retrieving token from identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.UNEXPECTED_ERROR_RETRIEVING_TOKEN, e, providerId);
}
}
@@ -243,7 +242,7 @@ public class IdentityBrokerService {
public Response consentTokenRetrieval(@PathParam("provider_id") String providerId,
MultivaluedMap formData) {
if (formData.containsKey("cancel")) {
- return redirectToErrorPage("Permission not approved.");
+ return redirectToErrorPage(Messages.PERMISSION_NOT_APPROVED);
}
return getToken(providerId, true);
@@ -262,7 +261,7 @@ public class IdentityBrokerService {
String relayState = identityProvider.getRelayState(createAuthenticationRequest(providerId, null));
if (relayState == null) {
- return redirectToErrorPage("No relay state in response from identity identity [" + providerId + ".");
+ return redirectToErrorPage(Messages.NO_RELAY_STATE_IN_RESPONSE, providerId);
}
if (isDebugEnabled()) {
@@ -298,10 +297,10 @@ public class IdentityBrokerService {
return performLocalAuthentication(identity, clientSessionCode);
} catch (IdentityBrokerException e) {
rollback();
- return redirectToErrorPage("Authentication failed. Could not authenticate with identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.IDENTITY_PROVIDER_AUTHENTICATION_FAILED, e, providerId);
} catch (Exception e) {
rollback();
- return redirectToErrorPage("Unexpected error when handling response from identity provider [" + providerId + "].", e);
+ return redirectToErrorPage(Messages.UNEXPECTED_ERROR_HANDLING_RESPONSE, e, providerId);
} finally {
if (this.session.getTransaction().isActive()) {
this.session.getTransaction().commit();
@@ -364,7 +363,7 @@ public class IdentityBrokerService {
this.event.event(EventType.IDENTITY_PROVIDER_ACCCOUNT_LINKING);
if (federatedUser != null) {
- return redirectToErrorPage("The identity returned by the identity provider [" + providerId + "] is already linked to other user.");
+ return redirectToErrorPage(Messages.IDENTITY_PROVIDER_ALREADY_LINKED, providerId);
}
UserModel authenticatedUser = clientSession.getUserSession().getUser();
@@ -375,12 +374,12 @@ public class IdentityBrokerService {
if (!authenticatedUser.isEnabled()) {
fireErrorEvent(Errors.USER_DISABLED);
- return redirectToErrorPage("User is disabled.");
+ return redirectToErrorPage(Messages.ACCOUNT_DISABLED);
}
if (!authenticatedUser.hasRole(this.realmModel.getApplicationByName(ACCOUNT_MANAGEMENT_APP).getRole(MANAGE_ACCOUNT))) {
fireErrorEvent(Errors.NOT_ALLOWED);
- return redirectToErrorPage("Insufficient permissions to link identities.");
+ return redirectToErrorPage(Messages.INSUFFICIENT_PERMISSION);
}
this.session.users().addFederatedIdentity(this.realmModel, authenticatedUser, federatedIdentityModel);
@@ -449,28 +448,28 @@ public class IdentityBrokerService {
return Urls.identityProviderAuthnResponse(this.uriInfo.getBaseUri(), providerId, this.realmModel.getName()).toString();
}
- private Response redirectToErrorPage(String message) {
- return redirectToErrorPage(message, null);
+ private Response redirectToErrorPage(String message, Object ... parameters) {
+ return redirectToErrorPage(message, null, parameters);
}
- private Response redirectToErrorPage(String message, Throwable throwable) {
+ private Response redirectToErrorPage(String message, Throwable throwable, Object ... parameters) {
if (message == null) {
- message = "Unexpected error when authenticating with identity provider";
+ message = Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR;
}
fireErrorEvent(message, throwable);
- return Flows.forwardToSecurityFailurePage(this.session, this.realmModel, this.uriInfo, message);
+ return Flows.forwardToSecurityFailurePage(this.session, this.realmModel, this.uriInfo, headers, message, parameters);
}
private Response redirectToLoginPage(Throwable t, ClientSessionCode clientCode) {
String message = t.getMessage();
if (message == null) {
- message = "Unexpected error when authenticating with identity provider";
+ message = Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR;
}
fireErrorEvent(message);
- return Flows.forms(this.session, this.realmModel, clientCode.getClientSession().getClient(), this.uriInfo)
+ return Flows.forms(this.session, this.realmModel, clientCode.getClientSession().getClient(), this.uriInfo, headers)
.setClientSessionCode(clientCode.getCode())
.setError(message)
.createLogin();
@@ -546,7 +545,7 @@ public class IdentityBrokerService {
if (existingUser != null) {
fireErrorEvent(Errors.FEDERATED_IDENTITY_EMAIL_EXISTS);
- throw new IdentityBrokerException("federatedIdentityEmailExists");
+ throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_EMAIL_EXISTS);
}
String username = updatedIdentity.getUsername();
@@ -554,7 +553,7 @@ public class IdentityBrokerService {
username = updatedIdentity.getEmail();
if (username == null || username.trim().length() == 0) {
fireErrorEvent(Errors.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
- throw new IdentityBrokerException("federatedIdentityRegistrationEmailMissing");
+ throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
// TODO KEYCLOAK-1053 (ask user to enter email address) should be implemented instead of plain exception as better solution for this case
}
username = username.trim();
@@ -566,7 +565,7 @@ public class IdentityBrokerService {
if (existingUser != null) {
fireErrorEvent(Errors.FEDERATED_IDENTITY_USERNAME_EXISTS);
- throw new IdentityBrokerException("federatedIdentityUsernameExists");
+ throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_USERNAME_EXISTS);
}
if (isDebugEnabled()) {
diff --git a/services/src/main/java/org/keycloak/services/resources/JsResource.java b/services/src/main/java/org/keycloak/services/resources/JsResource.java
index 6c59c78c04..1b0128805a 100755
--- a/services/src/main/java/org/keycloak/services/resources/JsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/JsResource.java
@@ -1,9 +1,11 @@
package org.keycloak.services.resources;
import org.keycloak.Config;
+import org.keycloak.Version;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
@@ -38,6 +40,17 @@ public class JsResource {
}
}
+ @GET
+ @Path("/{version}/keycloak.js")
+ @Produces("text/javascript")
+ public Response getJsWithVersion(@PathParam("version") String version) {
+ if (!version.equals(Version.RESOURCES_VERSION)) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return getJs();
+ }
+
@GET
@Path("/keycloak.min.js")
@Produces("text/javascript")
@@ -54,4 +67,15 @@ public class JsResource {
}
}
+ @GET
+ @Path("/{version}/keycloak.min.js")
+ @Produces("text/javascript")
+ public Response getMinJsWithVersion(@PathParam("version") String version) {
+ if (!version.equals(Version.RESOURCES_VERSION)) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return getMinJs();
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 812696f0d6..b4554ba8c9 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -32,15 +32,8 @@ import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.login.LoginFormsProvider;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RequiredCredentialModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
import org.keycloak.models.UserModel.RequiredAction;
-import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.protocol.LoginProtocol;
@@ -160,7 +153,7 @@ public class LoginActionsService {
return false;
} else if (!clientCode.isValid(requiredAction)) {
event.error(Errors.INVALID_CODE);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid code, please login again through your application.");
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_CODE);
return false;
} else {
return true;
@@ -172,7 +165,7 @@ public class LoginActionsService {
return false;
} else if (!(clientCode.isValid(requiredAction) || clientCode.isValid(alternativeRequiredAction))) {
event.error(Errors.INVALID_CODE);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid code, please login again through your application.");
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo,headers, Messages.INVALID_CODE);
return false;
} else {
return true;
@@ -182,18 +175,18 @@ public class LoginActionsService {
public boolean check(String code) {
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
return false;
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
return false;
}
clientCode = ClientSessionCode.parse(code, session, realm);
if (clientCode == null) {
event.error(Errors.INVALID_CODE);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
+ response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE);
return false;
}
return true;
@@ -224,7 +217,7 @@ public class LoginActionsService {
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
}
- LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo)
+ LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers)
.setClientSessionCode(clientSessionCode.getCode());
return forms.createLogin();
@@ -242,7 +235,7 @@ public class LoginActionsService {
event.event(EventType.REGISTER);
if (!realm.isRegistrationAllowed()) {
event.error(Errors.REGISTRATION_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Registration not allowed");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED);
}
Checks checks = new Checks();
@@ -256,7 +249,7 @@ public class LoginActionsService {
authManager.expireIdentityCookie(realm, uriInfo, clientConnection);
- return Flows.forms(session, realm, clientSession.getClient(), uriInfo)
+ return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers)
.setClientSessionCode(clientSessionCode.getCode())
.createRegistration();
}
@@ -276,17 +269,17 @@ public class LoginActionsService {
event.event(EventType.LOGIN);
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
if (clientCode == null) {
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE);
}
ClientSessionModel clientSession = clientCode.getClientSession();
@@ -295,7 +288,7 @@ public class LoginActionsService {
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE) || clientSession.getUserSession() != null) {
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
- return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo).setError(Messages.EXPIRED_CODE)
+ return Flows.forms(this.session, realm, clientSession.getClient(), uriInfo, headers).setError(Messages.EXPIRED_CODE)
.setClientSessionCode(clientCode.getCode())
.createLogin();
}
@@ -319,17 +312,18 @@ public class LoginActionsService {
ClientModel client = clientSession.getClient();
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown login requester.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
event.error(Errors.CLIENT_NOT_FOUND);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Login requester not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
if (formData.containsKey("cancel")) {
event.error(Errors.REJECTED_BY_USER);
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
return protocol.cancelLogin(clientSession);
}
@@ -356,14 +350,14 @@ public class LoginActionsService {
return authManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
case ACCOUNT_TEMPORARILY_DISABLED:
event.error(Errors.USER_TEMPORARILY_DISABLED);
- return Flows.forms(this.session, realm, client, uriInfo)
+ return Flows.forms(this.session, realm, client, uriInfo, headers)
.setError(Messages.ACCOUNT_TEMPORARILY_DISABLED)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
.createLogin();
case ACCOUNT_DISABLED:
event.error(Errors.USER_DISABLED);
- return Flows.forms(this.session, realm, client, uriInfo)
+ return Flows.forms(this.session, realm, client, uriInfo, headers)
.setError(Messages.ACCOUNT_DISABLED)
.setClientSessionCode(clientCode.getCode())
.setFormData(formData).createLogin();
@@ -373,19 +367,19 @@ public class LoginActionsService {
String passwordToken = new JWSBuilder().jsonContent(new PasswordToken(realm.getName(), user.getId())).rsa256(realm.getPrivateKey());
formData.add(CredentialRepresentation.PASSWORD_TOKEN, passwordToken);
- return Flows.forms(this.session, realm, client, uriInfo)
+ return Flows.forms(this.session, realm, client, uriInfo, headers)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
.createLoginTotp();
case INVALID_USER:
event.error(Errors.USER_NOT_FOUND);
- return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.INVALID_USER)
+ return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.INVALID_USER)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
.createLogin();
default:
event.error(Errors.INVALID_USER_CREDENTIALS);
- return Flows.forms(this.session, realm, client, uriInfo).setError(Messages.INVALID_USER)
+ return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.INVALID_USER)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
.createLogin();
@@ -407,25 +401,25 @@ public class LoginActionsService {
event.event(EventType.REGISTER);
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
if (!realm.isRegistrationAllowed()) {
event.error(Errors.REGISTRATION_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Registration not allowed");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REGISTRATION_NOT_ALLOWED);
}
ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
if (clientCode == null) {
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE);
}
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE)) {
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid code, please login again through your application.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_CODE);
}
String username = formData.getFirst("username");
@@ -444,17 +438,17 @@ public class LoginActionsService {
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
ClientModel client = clientSession.getClient();
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown login requester.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
event.error(Errors.CLIENT_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Login requester not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
@@ -464,15 +458,20 @@ public class LoginActionsService {
}
// Validate here, so user is not created if password doesn't validate to passwordPolicy of current realm
- String error = Validation.validateRegistrationForm(realm, formData, requiredCredentialTypes);
- if (error == null) {
- error = Validation.validatePassword(formData, realm.getPasswordPolicy());
+ String errorMessage = Validation.validateRegistrationForm(realm, formData, requiredCredentialTypes);
+ Object[] parameters = new Object[0];
+ if (errorMessage == null) {
+ PasswordPolicy.Error error = Validation.validatePassword(formData, realm.getPasswordPolicy());
+ if(error != null){
+ errorMessage = error.getMessage();
+ parameters = error.getParameters();
+ }
}
- if (error != null) {
+ if (errorMessage != null) {
event.error(Errors.INVALID_REGISTRATION);
- return Flows.forms(session, realm, client, uriInfo)
- .setError(error)
+ return Flows.forms(session, realm, client, uriInfo, headers)
+ .setError(errorMessage, parameters)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
.createRegistration();
@@ -481,7 +480,7 @@ public class LoginActionsService {
// Validate that user with this username doesn't exist in realm or any federation provider
if (session.users().getUserByUsername(username, realm) != null) {
event.error(Errors.USERNAME_IN_USE);
- return Flows.forms(session, realm, client, uriInfo)
+ return Flows.forms(session, realm, client, uriInfo, headers)
.setError(Messages.USERNAME_EXISTS)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
@@ -491,7 +490,7 @@ public class LoginActionsService {
// Validate that user with this email doesn't exist in realm or any federation provider
if (session.users().getUserByEmail(email, realm) != null) {
event.error(Errors.EMAIL_IN_USE);
- return Flows.forms(session, realm, client, uriInfo)
+ return Flows.forms(session, realm, client, uriInfo, headers)
.setError(Messages.EMAIL_EXISTS)
.setFormData(formData)
.setClientSessionCode(clientCode.getCode())
@@ -512,9 +511,14 @@ public class LoginActionsService {
boolean passwordUpdateSuccessful;
String passwordUpdateError = null;
+ Object[] passwordUpdateErrorParameters = null;
try {
session.users().updateCredential(realm, user, UserCredentialModel.password(formData.getFirst("password")));
passwordUpdateSuccessful = true;
+ } catch (ModelException me) {
+ passwordUpdateSuccessful = false;
+ passwordUpdateError = me.getMessage();
+ passwordUpdateErrorParameters = me.getParameters();
} catch (Exception ape) {
passwordUpdateSuccessful = false;
passwordUpdateError = ape.getMessage();
@@ -523,8 +527,8 @@ public class LoginActionsService {
// User already registered, but force him to update password
if (!passwordUpdateSuccessful) {
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
- return Flows.forms(session, realm, client, uriInfo)
- .setError(passwordUpdateError)
+ return Flows.forms(session, realm, client, uriInfo, headers)
+ .setError(passwordUpdateError, passwordUpdateErrorParameters)
.setClientSessionCode(clientCode.getCode())
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
}
@@ -552,7 +556,7 @@ public class LoginActionsService {
if (!checkSsl()) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
}
String code = formData.getFirst("code");
@@ -560,7 +564,7 @@ public class LoginActionsService {
ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
if (accessCode == null || !accessCode.isValid(ClientSessionModel.Action.OAUTH_GRANT)) {
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid access code.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.INVALID_ACCESS_CODE);
}
ClientSessionModel clientSession = accessCode.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
@@ -582,14 +586,15 @@ public class LoginActionsService {
}
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
- AuthenticationManager.logout(session, realm, userSession, uriInfo, clientConnection);
+ AuthenticationManager.logout(session, realm, userSession, uriInfo, clientConnection, headers);
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Session not active");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.SESSION_NOT_ACTIVE);
}
event.session(userSession);
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
protocol.setRealm(realm)
+ .setHttpHeaders(headers)
.setUriInfo(uriInfo);
if (formData.containsKey("cancel")) {
event.error(Errors.REJECTED_BY_USER);
@@ -620,7 +625,7 @@ public class LoginActionsService {
String error = Validation.validateUpdateProfileForm(formData);
if (error != null) {
- return Flows.forms(session, realm, null, uriInfo).setUser(user).setError(error)
+ return Flows.forms(session, realm, null, uriInfo, headers).setUser(user).setError(error)
.setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.UPDATE_PROFILE);
}
@@ -638,7 +643,7 @@ public class LoginActionsService {
// check for duplicated email
if (userByEmail != null && !userByEmail.getId().equals(user.getId())) {
- return Flows.forms(session, realm, null, uriInfo).setUser(user).setError(Messages.EMAIL_EXISTS)
+ return Flows.forms(session, realm, null, uriInfo, headers).setUser(user).setError(Messages.EMAIL_EXISTS)
.setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.UPDATE_PROFILE);
}
@@ -677,7 +682,7 @@ public class LoginActionsService {
String totp = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret");
- LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo).setUser(user);
+ LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo, headers).setUser(user);
if (Validation.isEmpty(totp)) {
return loginForms.setError(Messages.MISSING_TOTP)
.setClientSessionCode(accessCode.getCode())
@@ -722,7 +727,7 @@ public class LoginActionsService {
String passwordNew = formData.getFirst("password-new");
String passwordConfirm = formData.getFirst("password-confirm");
- LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo).setUser(user);
+ LoginFormsProvider loginForms = Flows.forms(session, realm, null, uriInfo, headers).setUser(user);
if (Validation.isEmpty(passwordNew)) {
return loginForms.setError(Messages.MISSING_PASSWORD)
.setClientSessionCode(accessCode.getCode())
@@ -735,6 +740,10 @@ public class LoginActionsService {
try {
session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew));
+ } catch (ModelException me) {
+ return loginForms.setError(me.getMessage(), me.getParameters())
+ .setClientSessionCode(accessCode.getCode())
+ .createResponse(RequiredAction.UPDATE_PASSWORD);
} catch (Exception ape) {
return loginForms.setError(ape.getMessage())
.setClientSessionCode(accessCode.getCode())
@@ -748,7 +757,7 @@ public class LoginActionsService {
if (clientSession.getAction().equals(ClientSessionModel.Action.RECOVER_PASSWORD)) {
String actionCookieValue = getActionCookie();
if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) {
- return Flows.forms(session, realm, clientSession.getClient(), uriInfo).setSuccess("passwordUpdated").createInfoPage();
+ return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers).setSuccess(Messages.ACCOUNT_PASSWORD_UPDATED).createInfoPage();
}
}
@@ -780,7 +789,7 @@ public class LoginActionsService {
String actionCookieValue = getActionCookie();
if (actionCookieValue == null || !actionCookieValue.equals(userSession.getId())) {
- return Flows.forms(session, realm, clientSession.getClient(), uriInfo).setSuccess("emailVerified").createInfoPage();
+ return Flows.forms(session, realm, clientSession.getClient(), uriInfo, headers).setSuccess(Messages.EMAIL_VERIFIED).createInfoPage();
}
event = event.clone().removeDetail(Details.EMAIL).event(EventType.LOGIN);
@@ -798,7 +807,7 @@ public class LoginActionsService {
createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
- return Flows.forms(session, realm, null, uriInfo)
+ return Flows.forms(session, realm, null, uriInfo, headers)
.setClientSessionCode(accessCode.getCode())
.setUser(userSession.getUser())
.createResponse(RequiredAction.VERIFY_EMAIL);
@@ -815,11 +824,11 @@ public class LoginActionsService {
return checks.response;
}
ClientSessionCode accessCode = checks.clientCode;
- return Flows.forms(session, realm, null, uriInfo)
+ return Flows.forms(session, realm, null, uriInfo, headers)
.setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.UPDATE_PASSWORD);
} else {
- return Flows.forms(session, realm, null, uriInfo)
+ return Flows.forms(session, realm, null, uriInfo, headers)
.setClientSessionCode(code)
.createPasswordReset();
}
@@ -832,16 +841,16 @@ public class LoginActionsService {
final MultivaluedMap formData) {
event.event(EventType.SEND_RESET_PASSWORD);
if (!checkSsl()) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.HTTPS_REQUIRED);
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.REALM_NOT_ENABLED);
}
ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
if (accessCode == null) {
event.error(Errors.INVALID_CODE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_CODE);
}
ClientSessionModel clientSession = accessCode.getClientSession();
@@ -849,12 +858,10 @@ public class LoginActionsService {
ClientModel client = clientSession.getClient();
if (client == null) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo,
- "Unknown login requester.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.UNKNOWN_LOGIN_REQUESTER);
}
if (!client.isEnabled()) {
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo,
- "Login requester not enabled.");
+ return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, headers, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
event.client(client.getClientId())
@@ -897,7 +904,7 @@ public class LoginActionsService {
} catch (EmailException e) {
event.error(Errors.EMAIL_SEND_FAILED);
logger.error("Failed to send password reset email", e);
- return Flows.forms(this.session, realm, client, uriInfo).setError("emailSendError")
+ return Flows.forms(this.session, realm, client, uriInfo, headers).setError(Messages.EMAIL_SENT_ERROR)
.setClientSessionCode(accessCode.getCode())
.createErrorPage();
}
@@ -905,7 +912,7 @@ public class LoginActionsService {
createActionCookie(realm, uriInfo, clientConnection, userSession.getId());
}
- return Flows.forms(session, realm, client, uriInfo).setSuccess("emailSent").setClientSessionCode(accessCode.getCode()).createPasswordReset();
+ return Flows.forms(session, realm, client, uriInfo, headers).setSuccess(Messages.EMAIL_SENT).setClientSessionCode(accessCode.getCode()).createPasswordReset();
}
private String getActionCookie() {
diff --git a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
index 488774d275..5fe27a4117 100755
--- a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources;
import org.jboss.logging.Logger;
import org.keycloak.Config;
+import org.keycloak.Version;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.models.KeycloakSession;
@@ -38,7 +39,11 @@ public class ThemeResource {
*/
@GET
@Path("/{version}/{themeType}/{themeName}/{path:.*}")
- public Response getResource(@PathParam("themeType") String themType, @PathParam("themeName") String themeName, @PathParam("path") String path) {
+ public Response getResource(@PathParam("version") String version, @PathParam("themeType") String themType, @PathParam("themeName") String themeName, @PathParam("path") String path) {
+ if (!version.equals(Version.RESOURCES_VERSION)) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
try {
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme = themeProvider.getTheme(themeName, Theme.Type.valueOf(themType.toUpperCase()));
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
index ff6e0fcbfa..362f72a7f4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
@@ -8,6 +8,7 @@ import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.ClientConnection;
import org.keycloak.Config;
+import org.keycloak.Version;
import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
import org.keycloak.freemarker.FreeMarkerException;
import org.keycloak.freemarker.FreeMarkerUtil;
@@ -290,6 +291,7 @@ public class AdminConsole {
map.put("authUrl", authUrl);
map.put("resourceUrl", Urls.themeRoot(baseUri) + "/admin/" + adminTheme);
+ map.put("resourceVersion", Version.RESOURCES_VERSION);
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme = themeProvider.getTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
index 8c9e4d4b65..3d0697db8a 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Flows.java
@@ -26,6 +26,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -37,16 +38,16 @@ public class Flows {
private Flows() {
}
- public static LoginFormsProvider forms(KeycloakSession session, RealmModel realm, ClientModel client, UriInfo uriInfo) {
- return session.getProvider(LoginFormsProvider.class).setRealm(realm).setUriInfo(uriInfo).setClient(client);
+ public static LoginFormsProvider forms(KeycloakSession session, RealmModel realm, ClientModel client, UriInfo uriInfo, HttpHeaders headers) {
+ return session.getProvider(LoginFormsProvider.class).setRealm(realm).setUriInfo(uriInfo).setClient(client).setHttpHeaders(headers);
}
public static ErrorFlows errors() {
return new ErrorFlows();
}
- public static Response forwardToSecurityFailurePage(KeycloakSession session, RealmModel realm, UriInfo uriInfo, String message) {
- return Flows.forms(session, realm, null, uriInfo).setError(message).createErrorPage();
+ public static Response forwardToSecurityFailurePage(KeycloakSession session, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String message, Object ... parameters) {
+ return Flows.forms(session, realm, null, uriInfo, headers).setError(message,parameters).createErrorPage();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java b/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java
index 7d3eef017d..2ccb4a004a 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/OAuthRedirect.java
@@ -34,7 +34,8 @@ public class OAuthRedirect extends AbstractOAuthClient {
UriBuilder uriBuilder = UriBuilder.fromUri(authUrl)
.queryParam(OAuth2Constants.CLIENT_ID, clientId)
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
- .queryParam(OAuth2Constants.STATE, state);
+ .queryParam(OAuth2Constants.STATE, state)
+ .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE);
if (scope != null) {
uriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
index 7889388fc9..ab56f4d7db 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java
@@ -190,6 +190,10 @@ public class Urls {
return requiredActionsBase(baseUri).path(LoginActionsService.class, "processConsent").build(realmId);
}
+ public static String localeCookiePath(URI baseUri, String realmName){
+ return realmBase(baseUri).path(realmName).build().getRawPath();
+ }
+
public static URI themeRoot(URI baseUri) {
return themeBase(baseUri).path(Version.RESOURCES_VERSION).build();
}
diff --git a/services/src/main/java/org/keycloak/services/validation/Validation.java b/services/src/main/java/org/keycloak/services/validation/Validation.java
index 254cee1e8c..f72a63023a 100755
--- a/services/src/main/java/org/keycloak/services/validation/Validation.java
+++ b/services/src/main/java/org/keycloak/services/validation/Validation.java
@@ -48,8 +48,8 @@ public class Validation {
return null;
}
- public static String validatePassword(MultivaluedMap formData, PasswordPolicy policy) {
- return policy.validate(formData.getFirst("password"));
+ public static PasswordPolicy.Error validatePassword(MultivaluedMap formData, PasswordPolicy policy) {
+ return policy.validate(formData.getFirst("username"), formData.getFirst("password"));
}
public static String validateUpdateProfileForm(MultivaluedMap formData) {
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
index d5e1c375a6..73c78e0589 100755
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
@@ -46,12 +46,27 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Stian Thorgersen
*/
public class KeycloakServer {
+ static {
+ try {
+ File f = new File(System.getProperty("user.home"), ".keycloak-test.properties");
+ if (f.isFile()) {
+ Properties p = new Properties();
+ p.load(new FileInputStream(f));
+ System.getProperties().putAll(p);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private static final Logger log = Logger.getLogger(KeycloakServer.class);
private boolean sysout = false;
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java
index d739b6c3a8..4c3fab61d2 100644
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/EmbeddedServersFactory.java
@@ -1,5 +1,8 @@
package org.keycloak.testutils.ldap;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* Factory for ApacheDS based LDAP and Kerberos servers
*
@@ -21,6 +24,7 @@ public class EmbeddedServersFactory {
private String baseDN;
private String bindHost;
private int bindPort;
+ private String ldapSaslPrincipal;
private String ldifFile;
private String kerberosRealm;
private int kdcPort;
@@ -39,6 +43,7 @@ public class EmbeddedServersFactory {
this.bindHost = System.getProperty("ldap.host");
String bindPort = System.getProperty("ldap.port");
this.ldifFile = System.getProperty("ldap.ldif");
+ this.ldapSaslPrincipal = System.getProperty("ldap.saslPrincipal");
this.kerberosRealm = System.getProperty("kerberos.realm");
String kdcPort = System.getProperty("kerberos.port");
@@ -62,6 +67,16 @@ public class EmbeddedServersFactory {
if (kdcEncryptionTypes == null || kdcEncryptionTypes.isEmpty()) {
kdcEncryptionTypes = DEFAULT_KDC_ENCRYPTION_TYPES;
}
+
+ if (ldapSaslPrincipal == null || ldapSaslPrincipal.isEmpty()) {
+ try {
+ // Same algorithm like sun.security.krb5.PrincipalName constructor
+ String canonicalHost = (InetAddress.getByName(bindHost)).getCanonicalHostName();
+ this.ldapSaslPrincipal = "ldap/" + canonicalHost + "@" + kerberosRealm;
+ } catch (UnknownHostException uhe) {
+ throw new RuntimeException(uhe);
+ }
+ }
}
@@ -72,7 +87,7 @@ public class EmbeddedServersFactory {
ldifFile = DEFAULT_LDIF_FILE;
}
- return new LDAPEmbeddedServer(baseDN, bindHost, bindPort, ldifFile);
+ return new LDAPEmbeddedServer(baseDN, bindHost, bindPort, ldifFile, ldapSaslPrincipal);
}
@@ -83,6 +98,6 @@ public class EmbeddedServersFactory {
ldifFile = DEFAULT_KERBEROS_LDIF_FILE;
}
- return new KerberosEmbeddedServer(baseDN, bindHost, bindPort, ldifFile, kerberosRealm, kdcPort, kdcEncryptionTypes);
+ return new KerberosEmbeddedServer(baseDN, bindHost, bindPort, ldifFile, ldapSaslPrincipal, kerberosRealm, kdcPort, kdcEncryptionTypes);
}
}
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java
index f5683425c0..63cc027f7f 100644
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/KerberosEmbeddedServer.java
@@ -2,6 +2,7 @@ package org.keycloak.testutils.ldap;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -48,8 +49,8 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
}
- protected KerberosEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile, String kerberosRealm, int kdcPort, String kdcEncryptionTypes) {
- super(baseDN, bindHost, bindPort, ldifFile);
+ protected KerberosEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile, String ldapSaslPrincipal, String kerberosRealm, int kdcPort, String kdcEncryptionTypes) {
+ super(baseDN, bindHost, bindPort, ldifFile, ldapSaslPrincipal);
this.kdcEncryptionTypes = kdcEncryptionTypes;
this.kerberosRealm = kerberosRealm;
this.kdcPort = kdcPort;
@@ -79,7 +80,8 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
LdapServer ldapServer = super.createLdapServer();
ldapServer.setSaslHost( this.bindHost );
- ldapServer.setSaslPrincipal( "ldap/" + this.bindHost + "@" + this.kerberosRealm);
+ ldapServer.setSaslPrincipal( this.ldapSaslPrincipal);
+ ldapServer.setSaslRealms(new ArrayList());
ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.PLAIN, new PlainMechanismHandler());
ldapServer.addSaslMechanismHandler(SupportedSaslMechanisms.CRAM_MD5, new CramMd5MechanismHandler());
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java
index 4fde15bd3e..e6e7be1b1d 100644
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPEmbeddedServer.java
@@ -2,7 +2,6 @@ package org.keycloak.testutils.ldap;
import java.io.File;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -35,6 +34,7 @@ public class LDAPEmbeddedServer {
protected final String bindHost;
protected final int bindPort;
protected final String ldifFile;
+ protected final String ldapSaslPrincipal;
protected DirectoryService directoryService;
protected LdapServer ldapServer;
@@ -47,16 +47,19 @@ public class LDAPEmbeddedServer {
ldapEmbeddedServer.start();
}
- public LDAPEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile) {
+ public LDAPEmbeddedServer(String baseDN, String bindHost, int bindPort, String ldifFile, String ldapSaslPrincipal) {
this.baseDN = baseDN;
this.bindHost = bindHost;
this.bindPort = bindPort;
this.ldifFile = ldifFile;
+ this.ldapSaslPrincipal = ldapSaslPrincipal;
}
public void init() throws Exception {
- log.info("Creating LDAP Directory Service. Config: baseDN=" + baseDN + ", bindHost=" + bindHost + ", bindPort=" + bindPort);
+ log.info("Creating LDAP Directory Service. Config: baseDN=" + baseDN + ", bindHost=" + bindHost + ", bindPort=" + bindPort +
+ ", ldapSaslPrincipal=" + ldapSaslPrincipal);
+
this.directoryService = createDirectoryService();
log.info("Importing LDIF: " + ldifFile);
@@ -133,9 +136,6 @@ public class LDAPEmbeddedServer {
// Propagate the anonymous flag to the DS
directoryService.setAllowAnonymousAccess(false);
- ldapServer.setSaslHost( this.bindHost );
- ldapServer.setSaslPrincipal( "ldap/" + this.bindHost + "@KEYCLOAK.ORG");
- ldapServer.setSaslRealms(new ArrayList());
return ldapServer;
}
@@ -143,6 +143,7 @@ public class LDAPEmbeddedServer {
private void importLdif() throws Exception {
Map map = new HashMap();
map.put("hostname", this.bindHost);
+ map.put("ldapSaslPrincipal", this.ldapSaslPrincipal);
// For now, assume that LDIF file is on classpath
InputStream is = getClass().getClassLoader().getResourceAsStream(ldifFile);
diff --git a/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
index acdd570a68..fd9936cfa9 100644
--- a/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
+++ b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
@@ -32,7 +32,7 @@ cn: LDAP
sn: Service
uid: ldap
userPassword: randall
-krb5PrincipalName: ldap/${hostname}@KEYCLOAK.ORG
+krb5PrincipalName: ${ldapSaslPrincipal}
krb5KeyVersionNumber: 0
dn: uid=HTTP,ou=People,dc=keycloak,dc=org
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index a32a70dc1d..9319661732 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -67,10 +67,6 @@ public class OAuthClient {
private String realm = "test";
- private String responseType = OAuth2Constants.CODE;
-
- private String grantType = "authorization_code";
-
private String clientId = "test-app";
private String redirectUri = "http://localhost:8081/app/auth";
@@ -113,9 +109,8 @@ public class OAuthClient {
HttpPost post = new HttpPost(getAccessTokenUrl());
List parameters = new LinkedList();
- if (grantType != null) {
- parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, grantType));
- }
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
+
if (code != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
}
@@ -153,6 +148,7 @@ public class OAuthClient {
post.setHeader("Authorization", authorization);
List parameters = new LinkedList();
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
parameters.add(new BasicNameValuePair("username", username));
parameters.add(new BasicNameValuePair("password", password));
@@ -199,9 +195,8 @@ public class OAuthClient {
HttpPost post = new HttpPost(getRefreshTokenUrl());
List parameters = new LinkedList();
- if (grantType != null) {
- parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, grantType));
- }
+ parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
+
if (refreshToken != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
}
@@ -290,10 +285,8 @@ public class OAuthClient {
}
public String getLoginFormUrl() {
- UriBuilder b = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri(baseUrl));
- if (responseType != null) {
- b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
- }
+ UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(baseUrl));
+ b.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE);
if (clientId != null) {
b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
}
@@ -307,7 +300,7 @@ public class OAuthClient {
}
public String getAccessTokenUrl() {
- UriBuilder b = OIDCLoginProtocolService.accessCodeToTokenUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
@@ -323,12 +316,12 @@ public class OAuthClient {
}
public String getResourceOwnerPasswordCredentialGrantUrl() {
- UriBuilder b = OIDCLoginProtocolService.grantAccessTokenUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getRefreshTokenUrl() {
- UriBuilder b = OIDCLoginProtocolService.refreshUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
@@ -351,11 +344,6 @@ public class OAuthClient {
return this;
}
- public OAuthClient responseType(String responseType) {
- this.responseType = responseType;
- return this;
- }
-
public OAuthClient state(String state) {
this.state = state;
return this;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 6497cb50f1..4743826502 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -283,7 +283,7 @@ public class AccountTest {
// All fields are required, so there should be an error when something is missing.
profilePage.updateProfile("", "New last", "new@email.com");
- Assert.assertEquals("Please specify first name", profilePage.getError());
+ Assert.assertEquals("Please specify first name.", profilePage.getError());
Assert.assertEquals("", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail());
@@ -292,7 +292,7 @@ public class AccountTest {
profilePage.updateProfile("New first", "", "new@email.com");
- Assert.assertEquals("Please specify last name", profilePage.getError());
+ Assert.assertEquals("Please specify last name.", profilePage.getError());
Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail());
@@ -301,7 +301,7 @@ public class AccountTest {
profilePage.updateProfile("New first", "New last", "");
- Assert.assertEquals("Please specify email", profilePage.getError());
+ Assert.assertEquals("Please specify email.", profilePage.getError());
Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("", profilePage.getEmail());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
index 1d6665171b..0d6b4cfefc 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionEmailVerificationTest.java
@@ -236,7 +236,7 @@ public class RequiredActionEmailVerificationTest {
events.expectRequiredAction(EventType.VERIFY_EMAIL).session(sessionId).detail("email", "test-user@localhost").detail(Details.CODE_ID, mailCodeId).assertEvent();
assertTrue(infoPage.isCurrent());
- assertEquals("Email verified", infoPage.getInfo());
+ assertEquals("Your email address has been verified.", infoPage.getInfo());
loginPage.open();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
index d832f967ee..e5e4c3c3f3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionUpdateProfileTest.java
@@ -108,7 +108,7 @@ public class RequiredActionUpdateProfileTest {
updateProfilePage.assertCurrent();
- Assert.assertEquals("Please specify first name", updateProfilePage.getError());
+ Assert.assertEquals("Please specify first name.", updateProfilePage.getError());
events.assertEmpty();
}
@@ -125,7 +125,7 @@ public class RequiredActionUpdateProfileTest {
updateProfilePage.assertCurrent();
- Assert.assertEquals("Please specify last name", updateProfilePage.getError());
+ Assert.assertEquals("Please specify last name.", updateProfilePage.getError());
events.assertEmpty();
}
@@ -142,7 +142,7 @@ public class RequiredActionUpdateProfileTest {
updateProfilePage.assertCurrent();
- Assert.assertEquals("Please specify email", updateProfilePage.getError());
+ Assert.assertEquals("Please specify email.", updateProfilePage.getError());
events.assertEmpty();
}
@@ -159,7 +159,7 @@ public class RequiredActionUpdateProfileTest {
updateProfilePage.assertCurrent();
- Assert.assertEquals("Email already exists", updateProfilePage.getError());
+ Assert.assertEquals("Email already exists.", updateProfilePage.getError());
events.assertEmpty();
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index e1d83b32a3..cfc9534e7b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -92,7 +92,7 @@ public class AdapterTestStrategy extends ExternalResource {
@WebResource
protected InputPage inputPage;
- protected String LOGIN_URL = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri(AUTH_SERVER_URL)).build("demo").toString();
+ protected String LOGIN_URL = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_URL)).build("demo").toString();
public AdapterTestStrategy(String AUTH_SERVER_URL, String APP_SERVER_BASE_URL, AbstractKeycloakRule keycloakRule) {
this.AUTH_SERVER_URL = AUTH_SERVER_URL;
@@ -420,11 +420,12 @@ public class AdapterTestStrategy extends ExternalResource {
public void testBadUser() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_URL);
- URI uri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("demo");
+ URI uri = OIDCLoginProtocolService.tokenUrl(builder).build("demo");
WebTarget target = client.target(uri);
String header = BasicAuthHelper.createHeader("customer-portal", "password");
Form form = new Form();
- form.param("username", "monkey@redhat.com")
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+ .param("username", "monkey@redhat.com")
.param("password", "password");
Response response = target.request()
.header(HttpHeaders.AUTHORIZATION, header)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
index 54980c6960..632202d542 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
@@ -31,7 +31,7 @@ import org.openqa.selenium.WebDriver;
*/
public class CookieTokenStoreAdapterTest {
- public static final String LOGIN_URL = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
+ public static final String LOGIN_URL = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
@ClassRule
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
index 8d4b835d23..235d5f54c4 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenancyTest.java
@@ -126,7 +126,7 @@ public class MultiTenancyTest {
}
private void doTenantRequests(String tenant, boolean logout) {
- String tenantLoginUrl = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build(tenant).toString();
+ String tenantLoginUrl = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build(tenant).toString();
driver.navigate().to("http://localhost:8081/multi-tenant?realm="+tenant);
System.out.println("Current url: " + driver.getCurrentUrl());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
index cce65bd49e..01a5861350 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/RelativeUriAdapterTest.java
@@ -66,7 +66,7 @@ import java.util.Map;
*/
public class RelativeUriAdapterTest {
- public static final String LOGIN_URL = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
+ public static final String LOGIN_URL = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
public static PublicKey realmPublicKey;
@ClassRule
public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule(){
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index b1ae4cbe70..5b66f7f1df 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -175,7 +175,7 @@ public abstract class AbstractIdentityProviderTest {
driver.navigate().to("http://localhost:8081/test-app/logout");
driver.navigate().to("http://localhost:8081/test-app");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
} finally {
getRealm().setRegistrationEmailAsUsername(false);
@@ -215,7 +215,7 @@ public abstract class AbstractIdentityProviderTest {
this.driver.navigate().to("http://localhost:8081/test-app/");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
try {
this.driver.findElement(By.className(getProviderId()));
@@ -245,7 +245,7 @@ public abstract class AbstractIdentityProviderTest {
this.driver.navigate().to("http://localhost:8081/test-app/");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
try {
this.driver.findElement(By.className(getProviderId()));
@@ -267,7 +267,7 @@ public abstract class AbstractIdentityProviderTest {
public void testUserAlreadyExistsWhenUpdatingProfile() {
this.driver.navigate().to("http://localhost:8081/test-app/");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
// choose the identity provider
this.loginPage.clickSocial(getProviderId());
@@ -286,7 +286,7 @@ public abstract class AbstractIdentityProviderTest {
assertNotNull(element);
- assertEquals("Email already exists", element.getText());
+ assertEquals("Email already exists.", element.getText());
this.updateProfilePage.assertCurrent();
this.updateProfilePage.update("Test", "User", "test-user@redhat.com");
@@ -306,7 +306,7 @@ public abstract class AbstractIdentityProviderTest {
this.driver.navigate().to("http://localhost:8081/test-app/");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
// choose the identity provider
this.loginPage.clickSocial(getProviderId());
@@ -374,7 +374,7 @@ public abstract class AbstractIdentityProviderTest {
public void testIdentityProviderNotAllowed() {
this.driver.navigate().to("http://localhost:8081/test-app/");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
driver.findElement(By.className("model-oidc-idp"));
}
@@ -438,7 +438,7 @@ public abstract class AbstractIdentityProviderTest {
driver.navigate().to("http://localhost:8081/test-app/logout");
driver.navigate().to("http://localhost:8081/test-app");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
}
@Test
@@ -533,13 +533,13 @@ public abstract class AbstractIdentityProviderTest {
driver.navigate().to("http://localhost:8081/test-app/logout");
driver.navigate().to("http://localhost:8081/test-app");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
}
private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
driver.navigate().to("http://localhost:8081/test-app");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
// choose the identity provider
this.loginPage.clickSocial(getProviderId());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
index b46617eac4..bac23e8c2b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
@@ -74,7 +74,7 @@ public class IdentityProviderHintTest {
public void testInvalidIdentityProviderHint() {
this.driver.navigate().to("http://localhost:8081/test-app?k_idp_hint=invalid-idp-id");
- assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
assertEquals("Could not find an identity provider with the identifier [invalid-idp-id].", this.driver.findElement(By.className("instruction")).getText());
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
index 611c6bd10e..5f484dc8b2 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java
@@ -236,12 +236,12 @@ public class FederationProvidersIntegrationTest {
// check existing username
registerPage.register("firstName", "lastName", "email@mail.cz", "existing", "Password1", "Password1");
registerPage.assertCurrent();
- Assert.assertEquals("Username already exists", registerPage.getError());
+ Assert.assertEquals("Username already exists.", registerPage.getError());
// Check existing email
registerPage.register("firstName", "lastName", "existing@email.org", "nonExisting", "Password1", "Password1");
registerPage.assertCurrent();
- Assert.assertEquals("Email already exists", registerPage.getError());
+ Assert.assertEquals("Email already exists.", registerPage.getError());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index 75a83f4f8a..8c5a2f8b22 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -162,7 +162,7 @@ public class LoginTest {
loginPage.assertCurrent();
- Assert.assertEquals("Account is disabled, contact admin", loginPage.getError());
+ Assert.assertEquals("Account is disabled, contact admin.", loginPage.getError());
events.expectLogin().user(userId).session((String) null).error("user_disabled").detail(Details.USERNAME, "login-test").assertEvent();
} finally {
@@ -316,7 +316,7 @@ public class LoginTest {
loginPage.login("login@test.com", "password");
loginPage.assertCurrent();
- Assert.assertEquals("Login timeout. Please login again", loginPage.getError());
+ Assert.assertEquals("Login timeout. Please login again.", loginPage.getError());
events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails().detail(Details.CODE_ID, AssertEvents.isCodeId()).assertEvent();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
index 2d0657a438..b2ac90e04e 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
@@ -78,7 +78,7 @@ public class RegisterTest {
registerPage.register("firstName", "lastName", "registerExistingUser@email", "test-user@localhost", "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Username already exists", registerPage.getError());
+ Assert.assertEquals("Username already exists.", registerPage.getError());
events.expectRegister("test-user@localhost", "registerExistingUser@email").user((String) null).error("username_in_use").assertEvent();
}
@@ -92,7 +92,7 @@ public class RegisterTest {
registerPage.register("firstName", "lastName", "registerUserInvalidPasswordConfirm@email", "registerUserInvalidPasswordConfirm", "password", "invalid");
registerPage.assertCurrent();
- Assert.assertEquals("Password confirmation doesn't match", registerPage.getError());
+ Assert.assertEquals("Password confirmation doesn't match.", registerPage.getError());
events.expectRegister("registerUserInvalidPasswordConfirm", "registerUserInvalidPasswordConfirm@email").user((String) null).error("invalid_registration").assertEvent();
}
@@ -157,7 +157,7 @@ public class RegisterTest {
registerPage.register("firstName", "lastName", "registerUserMissingUsername@email", null, "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Please specify username", registerPage.getError());
+ Assert.assertEquals("Please specify username.", registerPage.getError());
events.expectRegister(null, "registerUserMissingUsername@email").removeDetail("username").error("invalid_registration").assertEvent();
}
@@ -170,12 +170,12 @@ public class RegisterTest {
registerPage.register("firstName", "lastName", null, "registerUserMissingEmail", "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Please specify email", registerPage.getError());
+ Assert.assertEquals("Please specify email.", registerPage.getError());
events.expectRegister("registerUserMissingEmail", null).removeDetail("email").error("invalid_registration").assertEvent();
registerPage.register("firstName", "lastName", "registerUserInvalidEmailemail", "registerUserInvalidEmail", "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Invalid email address", registerPage.getError());
+ Assert.assertEquals("Invalid email address.", registerPage.getError());
events.expectRegister("registerUserInvalidEmail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent();
}
@@ -205,7 +205,7 @@ public class RegisterTest {
registerPage.registerWithEmailAsUsername("firstName", "lastName", "test-user@localhost", "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Username already exists", registerPage.getError());
+ Assert.assertEquals("Username already exists.", registerPage.getError());
events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("username_in_use").assertEvent();
} finally {
@@ -224,12 +224,12 @@ public class RegisterTest {
registerPage.registerWithEmailAsUsername("firstName", "lastName", null, "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Please specify email", registerPage.getError());
+ Assert.assertEquals("Please specify email.", registerPage.getError());
events.expectRegister(null, null).removeDetail("username").removeDetail("email").error("invalid_registration").assertEvent();
registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserInvalidEmailemail", "password", "password");
registerPage.assertCurrent();
- Assert.assertEquals("Invalid email address", registerPage.getError());
+ Assert.assertEquals("Invalid email address.", registerPage.getError());
events.expectRegister("registerUserInvalidEmailemail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent();
} finally {
configureRelamRegistrationEmailAsUsername(false);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 7582e2094f..a96b660a54 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -504,7 +504,7 @@ public class ResetPasswordTest {
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).session(sessionId).detail(Details.USERNAME, username).assertEvent();
assertTrue(infoPage.isCurrent());
- assertEquals("Password updated", infoPage.getInfo());
+ assertEquals("Your password has been updated", infoPage.getInfo());
loginPage.open();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 506013b70b..dd32e7cef0 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -4,11 +4,14 @@ import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
+import org.keycloak.constants.KerberosConstants;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
@@ -16,6 +19,9 @@ import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderFactory;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
@@ -197,12 +203,16 @@ public class ImportTest extends AbstractModelTest {
Assert.assertEquals("localhost", smtpConfig.get("host"));
Assert.assertEquals("3025", smtpConfig.get("port"));
- // Test social config
- //FIXME: KEYCLOAK-883
-// Map socialConfig = realm.getSocialConfig();
-// Assert.assertTrue(socialConfig.size() == 2);
-// Assert.assertEquals("abc", socialConfig.get("google.key"));
-// Assert.assertEquals("def", socialConfig.get("google.secret"));
+ // Test identity providers
+ List identityProviders = realm.getIdentityProviders();
+ Assert.assertEquals(1, identityProviders.size());
+ IdentityProviderModel google = identityProviders.get(0);
+ Assert.assertEquals("google1", google.getId());
+ Assert.assertEquals("google", google.getProviderId());
+ Assert.assertEquals("Google", google.getName());
+ Assert.assertTrue(google.isEnabled());
+ Assert.assertEquals("googleId", google.getConfig().get("clientId"));
+ Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
// Test federation providers
List fedProviders = realm.getUserFederationProviders();
@@ -216,6 +226,23 @@ public class ImportTest extends AbstractModelTest {
// Assert that federation link wasn't created during import
UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
Assert.assertNull(factory.getInstance(session, null).getUserByUsername(realm, "wburke"));
+
+ // Test protocol mappers. Default application has all the builtin protocol mappers. OtherApp just gss credential
+ Assert.assertNotNull(application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+ Assert.assertNotNull(application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "email"));
+ Assert.assertNotNull(application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "given name"));
+ Assert.assertNull(application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME));
+
+ Assert.assertEquals(1, otherApp.getProtocolMappers().size());
+ Assert.assertNull(otherApp.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+ ProtocolMapperModel gssCredentialMapper = otherApp.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
+ Assert.assertEquals(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME, gssCredentialMapper.getName());
+ Assert.assertEquals( OIDCLoginProtocol.LOGIN_PROTOCOL, gssCredentialMapper.getProtocol());
+ Assert.assertEquals(UserSessionNoteMapper.PROVIDER_ID, gssCredentialMapper.getProtocolMapper());
+ String includeInAccessToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
+ String includeInIdToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
+ Assert.assertTrue(includeInAccessToken.equalsIgnoreCase("true"));
+ Assert.assertTrue(includeInIdToken == null || Boolean.parseBoolean(includeInIdToken) == false);
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 56538a738c..34342e04b9 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -149,7 +149,7 @@ public class AccessTokenTest {
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "invalid");
Assert.assertEquals(400, response.getStatusCode());
- AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_client_credentials").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID);
+ AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_client_credentials").clearDetails().user((String) null).session((String) null);
expectedEvent.assertEvent();
}
@@ -190,7 +190,7 @@ public class AccessTokenTest {
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
- events.expectCodeToToken(codeId, sessionId).removeDetail(Details.TOKEN_ID).client((String) null).user((String) null).session((String) null).removeDetail(Details.REFRESH_TOKEN_ID).error(Errors.INVALID_CODE).assertEvent();
+ events.expectCodeToToken(codeId, sessionId).removeDetail(Details.TOKEN_ID).user((String) null).session((String) null).removeDetail(Details.REFRESH_TOKEN_ID).error(Errors.INVALID_CODE).assertEvent();
events.clear();
}
@@ -222,7 +222,7 @@ public class AccessTokenTest {
Assert.assertEquals(400, response.getStatusCode());
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
- expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
+ expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).user((String) null);
expectedEvent.assertEvent();
events.clear();
@@ -254,7 +254,7 @@ public class AccessTokenTest {
Assert.assertEquals(400, response.getStatusCode());
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
- expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
+ expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).user((String) null);
expectedEvent.assertEvent();
events.clear();
@@ -335,7 +335,7 @@ public class AccessTokenTest {
public void testValidateAccessToken() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
URI validateUri = OIDCLoginProtocolService.validateAccessTokenUrl(builder).build("test");
@@ -392,7 +392,7 @@ public class AccessTokenTest {
public void testGrantAccessToken() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
{ // test checkSsl
@@ -421,6 +421,7 @@ public class AccessTokenTest {
{ // test null username
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD);
form.param("password", "password");
Response response = grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
@@ -432,6 +433,7 @@ public class AccessTokenTest {
{ // test no password
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD);
form.param("username", "test-user@localhost");
Response response = grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
@@ -443,6 +445,7 @@ public class AccessTokenTest {
{ // test invalid password
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD);
form.param("username", "test-user@localhost");
form.param("password", "invalid");
Response response = grantTarget.request()
@@ -598,7 +601,7 @@ public class AccessTokenTest {
public void testTokenMapping() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
{
KeycloakSession session = keycloakRule.startSession();
@@ -721,7 +724,8 @@ public class AccessTokenTest {
protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
- form.param("username", "test-user@localhost")
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+ .param("username", "test-user@localhost")
.param("password", "password");
return grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
index c75a030821..9aa884ffe8 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
@@ -108,7 +108,7 @@ public class OAuthRedirectUriTest {
oauth.openLoginForm();
Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("Invalid redirect_uri", errorPage.getError());
+ Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
} finally {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
@@ -133,7 +133,7 @@ public class OAuthRedirectUriTest {
oauth.openLoginForm();
Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("Invalid redirect_uri", errorPage.getError());
+ Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
} finally {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
@@ -158,7 +158,7 @@ public class OAuthRedirectUriTest {
oauth.openLoginForm();
Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("Invalid redirect_uri", errorPage.getError());
+ Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
} finally {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
@@ -184,7 +184,7 @@ public class OAuthRedirectUriTest {
oauth.openLoginForm();
Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("Invalid redirect_uri", errorPage.getError());
+ Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
}
@Test
@@ -244,7 +244,7 @@ public class OAuthRedirectUriTest {
Assert.assertTrue(loginPage.isCurrent());
} else {
Assert.assertTrue(errorPage.isCurrent());
- Assert.assertEquals("Invalid redirect_uri", errorPage.getError());
+ Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
}
if (expectValid) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
index 4f254307bd..3776c03d99 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java
@@ -97,7 +97,7 @@ public class RefreshTokenTest {
public void nullRefreshToken() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI uri = OIDCLoginProtocolService.refreshUrl(builder).build("test");
+ URI uri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget target = client.target(uri);
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
@@ -389,10 +389,10 @@ public class RefreshTokenTest {
public void testCheckSsl() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI uri = OIDCLoginProtocolService.refreshUrl(builder).build("test");
+ URI uri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget refreshTarget = client.target(uri);
String refreshToken = null;
@@ -452,6 +452,7 @@ public class RefreshTokenTest {
protected Response executeRefreshToken(WebTarget refreshTarget, String refreshToken) {
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN);
form.param("refresh_token", refreshToken);
return refreshTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
@@ -461,7 +462,8 @@ public class RefreshTokenTest {
protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
- form.param("username", "test-user@localhost")
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+ .param("username", "test-user@localhost")
.param("password", "password");
return grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index ea269c339d..7ab25689cb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -181,11 +181,9 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
events.expectLogin()
.client("resource-owner")
.session((String) null)
- .detail(Details.AUTH_METHOD, "oauth_credentials")
- .detail(Details.RESPONSE_TYPE, "token")
- .removeDetail(Details.CODE_ID)
- .removeDetail(Details.REDIRECT_URI)
+ .clearDetails()
.error(Errors.INVALID_CLIENT_CREDENTIALS)
+ .user((String) null)
.assertEvent();
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index eb52fbb80a..ce9a574435 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -24,6 +24,7 @@ package org.keycloak.testsuite.oidc;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.OAuth2Constants;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.AccessTokenResponse;
@@ -68,7 +69,7 @@ public class UserInfoTest {
public void testSuccessfulUserInfoRequest() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(grantTarget);
Response response = executeUserInfoRequest(accessTokenResponse.getToken());
@@ -99,7 +100,8 @@ public class UserInfoTest {
private AccessTokenResponse executeGrantAccessTokenRequest(WebTarget grantTarget) {
String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form();
- form.param("username", "test-user@localhost")
+ form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
+ .param("username", "test-user@localhost")
.param("password", "password");
Response response = grantTarget.request()
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
index 1766a8766c..fc83347637 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
@@ -56,7 +56,7 @@ public class LoginPage extends AbstractPage {
@FindBy(linkText = "Register")
private WebElement registerLink;
- @FindBy(linkText = "Password")
+ @FindBy(linkText = "Forgot Password?")
private WebElement resetPasswordLink;
@FindBy(linkText = "Username")
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
index be6d79d4e6..cdf61d0331 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
@@ -136,7 +136,7 @@ public class AccessTokenPerfTest {
}
public String getLoginFormUrl(String state) {
- UriBuilder b = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(baseUrl));
if (responseType != null) {
b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
}
@@ -204,7 +204,7 @@ public class AccessTokenPerfTest {
String authorization = BasicAuthHelper.createHeader(clientId, "password");
- String res = client.target(OIDCLoginProtocolService.accessCodeToTokenUrl(UriBuilder.fromUri(baseUrl)).build(realm)).request()
+ String res = client.target(OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl)).build(realm)).request()
.header(HttpHeaders.AUTHORIZATION, authorization)
.post(Entity.form(form), String.class);
count.incrementAndGet();
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index 8d36a576fc..f43c7fc610 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -15,12 +15,12 @@
"identityProviders" : [
{
"providerId" : "google",
- "id" : "google",
+ "id" : "google1",
"name" : "Google",
"enabled": true,
"config": {
- "clientId": "clientId",
- "clientSecret": "clientSecret"
+ "clientId": "googleId",
+ "clientSecret": "googleSecret"
}
}
],
@@ -111,9 +111,23 @@
},
{
"name": "OtherApp",
- "enabled": true
+ "enabled": true,
+ "protocolMappers" : [
+ {
+ "name" : "gss delegation credential",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+ "consentRequired" : true,
+ "consentText" : "gss delegation credential",
+ "config" : {
+ "user.session.note" : "gss_delegation_credential",
+ "access.token.claim" : "true",
+ "claim.name" : "gss_delegation_credential",
+ "Claim JSON Type" : "String"
+ }
+ }
+ ]
}
-
],
"oauthClients" : [
{
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/OAuthClient.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/OAuthClient.java
index 168456e339..d5d2379e57 100755
--- a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/OAuthClient.java
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/OAuthClient.java
@@ -199,7 +199,7 @@ public class OAuthClient {
}
public String getLoginFormUrl() {
- UriBuilder b = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(baseUrl));
if (responseType != null) {
b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
}
@@ -216,7 +216,7 @@ public class OAuthClient {
}
public String getAccessTokenUrl() {
- UriBuilder b = OIDCLoginProtocolService.accessCodeToTokenUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
@@ -232,12 +232,12 @@ public class OAuthClient {
}
public String getResourceOwnerPasswordCredentialGrantUrl() {
- UriBuilder b = OIDCLoginProtocolService.grantAccessTokenUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getRefreshTokenUrl() {
- UriBuilder b = OIDCLoginProtocolService.refreshUrl(UriBuilder.fromUri(baseUrl));
+ UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
diff --git a/testsuite/proxy/src/test/java/org/keycloak/testsuite/ProxyTest.java b/testsuite/proxy/src/test/java/org/keycloak/testsuite/ProxyTest.java
index 7443287087..a93d416793 100755
--- a/testsuite/proxy/src/test/java/org/keycloak/testsuite/ProxyTest.java
+++ b/testsuite/proxy/src/test/java/org/keycloak/testsuite/ProxyTest.java
@@ -188,7 +188,7 @@ public class ProxyTest {
@WebResource
protected LoginPage loginPage;
- public static final String LOGIN_URL = OIDCLoginProtocolService.loginPageUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
+ public static final String LOGIN_URL = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("demo").toString();
@Test
public void testHttp() throws Exception {