keycloak-memoizeit

Details

diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl
index e5a0a6e..4e7caac 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl
@@ -15,7 +15,7 @@
             </div>
             <div class="form-group">
                 <label for="email">${rb.getString('email')}</label><span class="required">*</span>
-                <input type="email" id="email" name="email" autofocus value="${user.email!''}"/>
+                <input type="text" id="email" name="email" autofocus value="${user.email!''}"/>
             </div>
             <div class="form-group">
                 <label for="lastName">${rb.getString('lastName')}</label><span class="required">*</span>
@@ -27,7 +27,7 @@
             </div>
         </fieldset>
         <div class="form-actions">
-            <a href="#">« Back to my application</a>
+            <#--a href="#">« Back to my application</a-->
             <button type="submit" class="primary">Save</button>
             <button type="submit">Cancel</button>
         </div>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/admin-console.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/admin-console.css
index af63a63..476a082 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/admin-console.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/admin-console.css
@@ -185,43 +185,6 @@ table a:hover {
   font-weight: normal;
   margin-left: 1em;
 }
-.tooltip-box {
-  position: absolute;
-  font-size: 1em;
-  background-image: url("img/tooltip-box-arrow-right-up.svg");
-  background-position: right top;
-  background-repeat: no-repeat;
-  padding-top: 1em;
-  right: 0;
-  top: 1.5em;
-  font-size: 0.90909090909091em;
-}
-.tooltip-box fieldset {
-  width: 30.8em;
-  padding-left: 1.5em;
-  padding-right: 1.5em;
-  padding-top: .5em;
-  background-color: #fff;
-  border: 1px solid #b6b6b6;
-  border-top: none;
-  border-radius: 0 2px 2px 2px;
-  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.15);
-}
-.tooltip-box fieldset legend {
-  display: none;
-}
-.tooltip-box fieldset label {
-  width: 6em;
-}
-.tooltip-box fieldset .form-actions {
-  margin: 0;
-  padding: 1em 1.5em 1em 0;
-  background-color: #f8f8f8;
-  display: block;
-  float: none;
-  margin-right: -1.5em;
-  margin-left: -1.5em;
-}
 td.token-cell button {
   margin-top: -1px;
 }
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/forms.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/forms.css
index 0d6bfbf..1dc3c5d 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/forms.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/forms.css
@@ -307,9 +307,7 @@ button[class^="icon-"] {
   padding: 0;
   line-height: 1em;
 }
-button[class^="icon-"]:hover {
-  background-image: url(img/sprites.png);
-}
+
 legend {
   font-size: 1em;
   border-width: 1px 0 0 0;
@@ -328,14 +326,7 @@ legend .text {
   font-weight: bold;
   font-size: 1.25em;
 }
-legend .icon-info {
-  background-image: url(img/sprites-gray.png);
-  margin-left: 1em;
-  vertical-align: baseline;
-}
-legend .icon-info:hover {
-  background-image: url(img/sprites.png);
-}
+
 .form-group {
   display: block;
   margin-bottom: 1em;
@@ -377,7 +368,7 @@ legend + table {
   margin-top: 1em;
 }
 .code {
-  font-family: Courier, ​monospace;
+  font-family: Courier, monospace;
 }
 .onoffswitch {
   -moz-user-select: none;
@@ -460,20 +451,6 @@ input[type="email"].tiny {
   min-width: 40px;
   width: 40px;
 }
-.select-rcue,
-.select2-container .select2-choice {
-  height: 26px;
-  border: 1px #b6b6b6 solid;
-  border-radius: 2px;
-  box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
-  color: #333;
-  background: #ffffff url(img/select-arrow.png) no-repeat right center;
-  overflow: hidden;
-  min-width: 75px;
-  padding: 0 0.9em 0 0;
-  display: inline-block;
-  font-family: "Open Sans", sans-serif;
-}
 .select-rcue:hover {
   border-color: #62afdb;
 }
@@ -510,93 +487,7 @@ input[type="email"].tiny {
 .select-rcue option:hover {
   background-color: #d5ecf9;
 }
-.select2-container {
-  float: left;
-  margin-top: 0.3em;
-  margin-bottom: 0.3em;
-}
-.select2-container .select2-choice > .select2-chosen {
-  line-height: 2.1em;
-  padding-left: 0.90909090909091em;
-  margin-right: 0;
-  font-size: 1.1em;
-  padding-right: 2.36363636363636em;
-  padding-right: 26px;
-}
-.select2-container .select2-choice .select2-arrow {
-  display: none;
-}
-.select2-dropdown-open {
-  background-color: #fff;
-}
-.select2-dropdown-open .select2-choice,
-.select2-dropdown-open .select2-choices {
-  border-bottom: none;
-  border-radius: 2px 2px 0 0;
-  background-image: url(img/chosen-arrow-down.png);
-  background-color: transparent;
-  background-repeat: no-repeat;
-  background-position: right top;
-  box-shadow: none;
-}
-.select2-dropdown-open .select2-choice,
-.select2-dropdown-open.select2-drop-above .select2-choice,
-.select2-dropdown-open .select2-choices,
-.select2-dropdown-open.select2-drop-above .select2-choices {
-  border-color: #62AFDB;
-}
-.select2-search input {
-  min-width: 0;
-}
-.select2-drop-active {
-  border-radius: 0 0 2px 2px;
-  margin-top: -1px;
-  padding-top: 4px;
-}
-.select2-container.select2-drop-above .select2-choice {
-  border-radius: 0 0 2px 2px;
-  background-image: url(img/chosen-arrow-up.png);
-  background-repeat: no-repeat;
-  background-position: right 0;
-  box-shadow: none;
-}
-.select2-drop.select2-drop-above {
-  border-radius: 2px 2px 0 0;
-  padding-top: 0;
-  margin-top: 2px;
-}
-.select2-drop.select2-drop-above.select2-drop-active,
-.select2-drop-active {
-  border-color: #62AFDB;
-}
-.select2-results {
-  padding-left: 0;
-  margin-right: 0;
-}
-.select2-results li {
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-}
-.select2-results .select2-result-label,
-.select2-results .select2-no-results,
-.select2-results .select2-searching,
-.select2-results .select2-selection-limit {
-  font-size: 1.1em;
-  padding-left: 1.09090909090909em;
-}
-.select2-results .select2-no-results,
-.select2-results .select2-searching,
-.select2-results .select2-selection-limit {
-  color: #838383;
-  padding-top: 3px;
-  padding-bottom: 4px;
-}
-.select2-results .select2-highlighted {
-  background-color: #d5ecf9;
-  border-top: 1px solid #a7d7f1;
-  border-bottom: 1px solid #a7d7f1;
-  color: #4d5258;
-}
+
 .input-group input + .select-rcue {
   border-radius: 0 2px 2px 0;
   border-left: 0;
@@ -605,93 +496,7 @@ input[type="email"].tiny {
 .input-select .input-group input {
   float: left;
 }
-.tokenfield.form-control {
-  width: 40em;
-  float: left;
-  min-height: 2.6em;
-  border: 1px #b6b6b6 solid;
-  border-radius: 2px;
-  box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
-  padding: 0 0.7em;
-  margin-bottom: 0;
-  font-size: 1em;
-  height: auto;
-  outline: 0 none;
-}
-.tokenfield.form-control .token {
-  display: inline-block;
-  background-color: #d4ecf8;
-  border: 1px solid #a3d7f0;
-  border-radius: 1px;
-  padding: 0 0.3em 0 0.7em;
-  margin-right: 0.7em;
-  margin-top: 0.3em;
-  margin-bottom: 0.3em;
-  outline: 0 none;
-}
-.tokenfield.form-control .token span {
-  float: left;
-  font-size: 1.1em;
-  line-height: 1.45454545454545em;
-}
-.tokenfield.form-control .token .close {
-  text-indent: -99999em;
-  width: 1.6em;
-  height: 1.6em;
-  line-height: 1.6em;
-  background: url(img/btn-close-blue.png) no-repeat center center;
-  margin-left: 0.3em;
-  padding: 0;
-  border: none;
-  font-size: 1em;
-  opacity: 1;
-}
-.tokenfield.form-control input {
-  padding: 0;
-  border: none;
-  font-size: 1.1em;
-  line-height: 1.63636363636364em;
-  height: 1.63636363636364em;
-  margin: 0.272727272727273em 0;
-  box-shadow: none;
-  outline: 0 none;
-  float: left;
-}
-.tokenfield.form-control:hover {
-  border-color: #62afdb;
-}
-.tokenfield.form-control:focus {
-  border-color: #62afdb;
-  box-shadow: #62afdb 0 0 5px;
-}
-.token {
-  float: left;
-  background-color: #d4ecf8;
-  border: 1px solid #a3d7f0;
-  border-radius: 1px;
-  padding: 0 0.3em 0 0.7em;
-  margin-right: 0.7em;
-  margin-top: 0.3em;
-  margin-bottom: 0.3em;
-  outline: 0 none;
-}
-.token span {
-  float: left;
-  font-size: 1.1em;
-  line-height: 1.45454545454545em;
-}
-.token .close {
-  text-indent: -9999999em;
-  width: 1.6em;
-  height: 1.6em;
-  line-height: 1.6em;
-  background: url(img/btn-close-blue.png) no-repeat center center;
-  margin-left: 0.3em;
-  padding: 0;
-  border: none;
-  font-size: 1em;
-  opacity: 1;
-}
+
 .form-actions {
   float: right;
   margin-top: 3em;
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png
new file mode 100644
index 0000000..5ea210c
Binary files /dev/null and b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png differ
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
index eca69a2..488259d 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
@@ -3,9 +3,9 @@ body {
   min-height: 60em;
   min-width: 120em;
 }
+
 .rcue-login-register {
   background-color: #1D2226;
-  background-image: url("img/login-screen-background.jpg");
   background-position: top left;
   background-size: auto;
   background-repeat: no-repeat;
@@ -17,6 +17,7 @@ body {
   /* Info area */
 
 }
+
 .rcue-login-register h1 a {
   position: absolute;
   top: 5em;
@@ -61,12 +62,12 @@ body {
   padding-right: 4.5em;
 }
 .rcue-login-register .form-area {
-  background-image: url(img/login-register-separator.svg);
+  background-image: url(img/login-register-separator.png);
   background-repeat: no-repeat;
   background-position: 40.2em center;
 }
 .rcue-login-register .form-area.social {
-  background-image: url(img/login-register-social-separators.svg);
+  background-image: url(img/login-register-social-separators.png);
   background-position: 39.6em center;
 }
 .rcue-login-register .section > p {
@@ -267,10 +268,6 @@ a.zocial:before {
 .rcue-login-register.register form > div.aside-btn p {
   line-height: 1.3em;
 }
-/* Customer login */
-.rcue-login-register.customer {
-  background-image: url("img/customer-login-screen-bg2.jpg");
-}
 .rcue-login-register p.powered {
   font-size: 1.1em;
   margin-top: 1.27272727272727em;
@@ -402,11 +399,6 @@ a.zocial:before {
 .rcue-login-register.email label {
   width: 6.78571428571429em;
 }
-.rcue-login-register.email .form-area.email {
-  background-position: 40.6em center;
-  background-image: url(img/login-register-email-separator.svg);
-  background-repeat: no-repeat;
-}
 .rcue-login-register.email .feedback.bottom-left {
   left: 38.3em;
 }
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/sprites.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/sprites.css
index 1a35f74..1c009b7 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/sprites.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/sprites.css
@@ -3,7 +3,6 @@
 	display: inline-block;
 	width: 16px;
 	height: 16px;
-	background-image: url(img/sprites.png); /* Modified by Gabriel */
 	background-repeat: no-repeat;
 	text-indent: -99999em;
 	margin-right: 0.5em;
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/tables.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/tables.css
index 15a1f34..b260561 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/tables.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/tables.css
@@ -30,14 +30,6 @@ table thead tr th {
 .rcue-table-actions {
   padding: 1px;
 }
-/*
-.rcue-table-actions button {
-  padding: 3px 8px;
-  font-size: 11px;
-  box-shadow: 1px 2px 2px #e3e3e3;
-  margin: 4px;
-}
-*/
 .rcue-table-number {
   text-align: right;
   width: 100px;
@@ -54,11 +46,7 @@ table thead tr th {
   background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fafafa), color-stop(1, 0, #eeeeee));
   border-bottom: 1px #cedede solid;
 }
-/*
-table tbody tr td:first-child {
-  color: #0099d3;
-}
-*/
+
 table thead tr th:last-child {
   border-right: none;
 }
@@ -70,12 +58,7 @@ table tbody tr:first-child td {
 table tbody tr td:last-child {
   border-right: none;
 }
-/*
-table tbody tr:hover {
-  cursor: pointer;
-  background-color: #ebebeb;
-}
-*/
+
 /* Styles from Gabriel */
 .rcue-table-actions button + button,
 .rcue-table-actions .button + button {
@@ -109,23 +92,7 @@ table tbody tr td.token-cell button {
   margin-bottom: 7px;
   margin-top: 8px;
 }
-table tbody.selectable-rows tr:hover {
-  cursor: pointer;
-  background-color: #ebebeb;
-}
-table tbody.selectable-rows tr:first-child td {
-  padding-top: 9px;
-}
-table tbody.selectable-rows tr.selected,
-table tbody.selectable-rows tr.selected:hover {
-  background-color: #eaf5fb;
-}
-table tbody.selectable-rows tr.selected td:first-child,
-table tbody.selectable-rows tr.selected:hover td:first-child {
-  background-image: url(img/icon-row-selected.svg);
-  background-position: 0.2em center;
-  background-repeat: no-repeat;
-}
+
 table tfoot tr {
   border-top: 1px solid #cecece;
 }
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/img/favicon.ico b/forms/src/main/resources/META-INF/resources/forms/theme/default/img/favicon.ico
new file mode 100644
index 0000000..cbb6124
Binary files /dev/null and b/forms/src/main/resources/META-INF/resources/forms/theme/default/img/favicon.ico differ
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl
index b2ae529..5c48264 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl
@@ -15,15 +15,15 @@
             </div>
             <div class="form-group">
                 <label for="password-new">${rb.getString('passwordNew')}</label>
-                <input type="password" id="password-new" name="password-new" placeholder="At least 6 characters" class="error">
+                <input type="password" id="password-new" name="password-new">
             </div>
             <div class="form-group">
                 <label for="password-confirm" class="two-lines">${rb.getString('passwordConfirm')}</label>
-                <input type="password" id="password-confirm" name="password-confirm" class="error">
+                <input type="password" id="password-confirm" name="password-confirm">
             </div>
         </fieldset>
         <div class="form-actions">
-            <a href="#">« Back to my application</a>
+            <#--a href="#">« Back to my application</a-->
             <button type="submit" class="primary">Save</button>
             <button type="submit">Cancel</button>
         </div>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
index 19a95ee..61e24a8 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/template-main.ftl
@@ -4,16 +4,15 @@
 <head>
     <meta charset="utf-8">
     <title>Edit Account - <#nested "title"></title>
+    <!-- TODO replace with actual logo once
     <link rel="icon" href="img/favicon.ico">
 
     <!-- Frameworks -->
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/reset.css">
-    <!--link rel="stylesheet" href="bootstrap-3.0.0-wip/css/bootstrap.css"-->
     <link href="${template.formsPath}/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
     <link href="${template.formsPath}/theme/${template.theme}/css/zocial/zocial.css" rel="stylesheet">
 
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/sprites.css">
-    <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/select2.css">
     <!-- TODO remove external links -->
     <link rel="stylesheet" href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic'>
 
@@ -21,16 +20,12 @@
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/base.css">
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/forms.css">
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/header.css">
-    <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/tabs.css">
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/icons.css">
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/tables.css">
 
     <!-- Page styles -->
     <link rel="stylesheet" href="${template.formsPath}/theme/${template.theme}/css/admin-console.css">
 
-    <script src="${template.formsPath}/lib/jquery/jquery-2.0.3.min.js"></script>
-    <script src="${template.formsPath}/lib/bootstrap/js/bootstrap.js"></script>
-
 </head>
 <body class="admin-console user ${bodyClass}">
 
@@ -70,7 +65,7 @@
                 <li class="<#if active=='password'>active</#if>"><a href="${url.passwordUrl}">Password</a></li>
                 <li class="<#if active=='totp'>active</#if>"><a href="${url.totpUrl}">Authenticator</a></li>
                 <#--<li class="<#if active=='social'>active</#if>"><a href="${url.socialUrl}">Social Accounts</a></li>-->
-                <li class="<#if active=='access'>active</#if>"><a href="${url.accessUrl}">Authorized Access</a></li>
+                <#--<li class="<#if active=='access'>active</#if>"><a href="${url.accessUrl}">Authorized Access</a></li>-->
             </ul>
         </div>
 
diff --git a/forms/src/main/resources/org/keycloak/forms/messages.properties b/forms/src/main/resources/org/keycloak/forms/messages.properties
index 8fb4f12..7c8b05f 100644
--- a/forms/src/main/resources/org/keycloak/forms/messages.properties
+++ b/forms/src/main/resources/org/keycloak/forms/messages.properties
@@ -61,4 +61,7 @@ emailUpdateHeader=Update password
 emailSent=You should receive an email shortly with further instructions.
 emailError=Invalid username or email.
 emailErrorInfo=Please, fill in the fields again.
-emailInstruction=Enter your username and email address and we will send you instructions on how to create a new password.
\ No newline at end of file
+emailInstruction=Enter your username and 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/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 2a54323..8857271 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -131,12 +131,20 @@ public class AccountService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
+
         UserModel user = getUser(true);
+
+        String error = Validation.validateUpdateProfileForm(formData);
+        if (error != null) {
+            return Flows.forms(realm, request, uriInfo).setUser(user).setError(error).forwardToAccount();
+        }
+
         user.setFirstName(formData.getFirst("firstName"));
         user.setLastName(formData.getFirst("lastName"));
         user.setEmail(formData.getFirst("email"));
 
-        return Flows.forms(realm, request, uriInfo).setUser(user).forwardToAccount();
+        return Flows.forms(realm, request, uriInfo).setUser(user).setError("accountUpdated")
+                .setErrorType(FormFlows.MessageType.SUCCESS).forwardToAccount();
     }
 
     @Path("totp-remove")
@@ -205,7 +213,8 @@ public class AccountService {
 
         realm.updateCredential(user, credentials);
 
-        return Flows.forms(realm, request, uriInfo).setUser(user).forwardToPassword();
+        return Flows.forms(realm, request, uriInfo).setUser(user).setError("accountPasswordUpdated")
+                .setErrorType(FormFlows.MessageType.SUCCESS).forwardToPassword();
     }
 
     @Path("login-redirect")
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
index 4f8e75a..5b1a827 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
@@ -39,6 +39,8 @@ import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
 import org.picketlink.idm.credential.util.TimeBasedOTP;
 
 /**
@@ -96,8 +98,18 @@ public class AccountTest {
         changePasswordPage.open();
         loginPage.login("test-user@localhost", "password");
 
+        changePasswordPage.changePassword("", "new-password", "new-password");
+
+        Assert.assertTrue(profilePage.isError());
+
+        changePasswordPage.changePassword("password", "new-password", "new-password2");
+
+        Assert.assertTrue(profilePage.isError());
+
         changePasswordPage.changePassword("password", "new-password", "new-password");
 
+        Assert.assertTrue(profilePage.isSuccess());
+
         changePasswordPage.logout();
 
         loginPage.open();
@@ -120,8 +132,31 @@ public class AccountTest {
         Assert.assertEquals("", profilePage.getLastName());
         Assert.assertEquals("test-user@localhost", profilePage.getEmail());
 
+        // All fields are required, so there should be an error when something is missing.
+        profilePage.updateProfile("", "New last", "new@email.com");
+
+        Assert.assertTrue(profilePage.isError());
+        Assert.assertEquals("", profilePage.getFirstName());
+        Assert.assertEquals("", profilePage.getLastName());
+        Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+
+        profilePage.updateProfile("New first", "", "new@email.com");
+
+        Assert.assertTrue(profilePage.isError());
+        Assert.assertEquals("", profilePage.getFirstName());
+        Assert.assertEquals("", profilePage.getLastName());
+        Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+
+        profilePage.updateProfile("New first", "New last", "");
+
+        Assert.assertTrue(profilePage.isError());
+        Assert.assertEquals("", profilePage.getFirstName());
+        Assert.assertEquals("", profilePage.getLastName());
+        Assert.assertEquals("test-user@localhost", profilePage.getEmail());
+
         profilePage.updateProfile("New first", "New last", "new@email.com");
 
+        Assert.assertTrue(profilePage.isSuccess());
         Assert.assertEquals("New first", profilePage.getFirstName());
         Assert.assertEquals("New last", profilePage.getLastName());
         Assert.assertEquals("new@email.com", profilePage.getEmail());
@@ -136,8 +171,15 @@ public class AccountTest {
 
         Assert.assertFalse(driver.getPageSource().contains("Remove Google"));
 
+        // Error with false code
+        totpPage.configure(totp.generate(totpPage.getTotpSecret()+"123"));
+
+        Assert.assertTrue(profilePage.isError());
+
         totpPage.configure(totp.generate(totpPage.getTotpSecret()));
 
+        Assert.assertTrue(profilePage.isSuccess());
+
         Assert.assertTrue(driver.getPageSource().contains("Remove Google"));
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 7c99e1b..a9f6495 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -44,6 +44,9 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
     @FindBy(css = "button[type=\"submit\"]")
     private WebElement submitButton;
 
+    @FindBy(css = ".feedback > p > strong")
+    private WebElement feedbackMessage;
+
     public void updateProfile(String firstName, String lastName, String email) {
         firstNameInput.clear();
         firstNameInput.sendKeys(firstName);
@@ -75,4 +78,11 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         driver.navigate().to(PATH);
     }
 
+    public boolean isSuccess(){
+        return feedbackMessage != null && "Success!".equals(feedbackMessage.getText());
+    }
+
+    public boolean isError(){
+        return feedbackMessage != null && "Error!".equals(feedbackMessage.getText());
+    }
 }