keycloak-uncached

Changes

Details

diff --git a/connections/jpa-liquibase/src/main/java/org/keycloak/connections/jpa/updater/liquibase/custom/AddRealmCodeSecret.java b/connections/jpa-liquibase/src/main/java/org/keycloak/connections/jpa/updater/liquibase/custom/AddRealmCodeSecret.java
new file mode 100644
index 0000000..76a02a7
--- /dev/null
+++ b/connections/jpa-liquibase/src/main/java/org/keycloak/connections/jpa/updater/liquibase/custom/AddRealmCodeSecret.java
@@ -0,0 +1,79 @@
+package org.keycloak.connections.jpa.updater.liquibase.custom;
+
+import liquibase.change.custom.CustomSqlChange;
+import liquibase.database.Database;
+import liquibase.database.jvm.JdbcConnection;
+import liquibase.exception.CustomChangeException;
+import liquibase.exception.SetupException;
+import liquibase.exception.ValidationErrors;
+import liquibase.resource.ResourceAccessor;
+import liquibase.statement.SqlStatement;
+import liquibase.statement.core.UpdateStatement;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.util.ArrayList;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AddRealmCodeSecret implements CustomSqlChange {
+
+    private String confirmationMessage;
+
+    @Override
+    public SqlStatement[] generateStatements(Database database) throws CustomChangeException {
+        try {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Generated codeSecret for realms: ");
+
+            Connection connection = ((JdbcConnection) (database.getConnection())).getWrappedConnection();
+            ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM REALM WHERE CODE_SECRET IS NULL");
+
+            ArrayList<SqlStatement> statements = new ArrayList<SqlStatement>();
+            while (resultSet.next()) {
+                String id = resultSet.getString(1);
+
+                UpdateStatement statement = new UpdateStatement(null, null, "REALM")
+                        .addNewColumnValue("CODE_SECRET", KeycloakModelUtils.generateCodeSecret())
+                        .setWhereClause("ID='" + id + "'");
+                statements.add(statement);
+
+                if (!resultSet.isFirst()) {
+                    sb.append(", ");
+                }
+                sb.append(id);
+            }
+
+            if (!statements.isEmpty()) {
+                confirmationMessage = sb.toString();
+            }
+
+            return statements.toArray(new SqlStatement[statements.size()]);
+        } catch (Exception e) {
+            throw new CustomChangeException("Failed to add realm code secret", e);
+        }
+    }
+
+    @Override
+    public String getConfirmationMessage() {
+        return confirmationMessage;
+    }
+
+    @Override
+    public void setUp() throws SetupException {
+
+    }
+
+    @Override
+    public void setFileOpener(ResourceAccessor resourceAccessor) {
+
+    }
+
+    @Override
+    public ValidationErrors validate(Database database) {
+        return null;
+    }
+
+}
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.1.0.Beta1.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.1.0.Beta1.xml
index 8344266..c94b206 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.1.0.Beta1.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.1.0.Beta1.xml
@@ -43,9 +43,10 @@
         </addColumn>
         <addColumn tableName="REALM">
             <column name="CERTIFICATE" type="VARCHAR(2048)"/>
+            <column name="CODE_SECRET" type="VARCHAR(255)"/>
         </addColumn>
         <addColumn tableName="CLIENT">
-            <column name="NODE_REREG_TIMEOUT" type="INT"/>
+            <column name="NODE_REREG_TIMEOUT" type="INT" defaultValue="0"/>
         </addColumn>
         <addPrimaryKey columnNames="CLIENT_ID, NAME" constraintName="CONSTRAINT_3C" tableName="CLIENT_ATTRIBUTES"/>
         <addPrimaryKey columnNames="CLIENT_SESSION, NAME" constraintName="CONSTRAINT_5E" tableName="CLIENT_SESSION_NOTE"/>
@@ -53,5 +54,6 @@
         <addForeignKeyConstraint baseColumnNames="CLIENT_ID" baseTableName="CLIENT_ATTRIBUTES" constraintName="FK3C47C64BEACCA966" referencedColumnNames="ID" referencedTableName="CLIENT"/>
         <addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_SESSION_NOTE" constraintName="FK5EDFB00FF51C2736" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
         <addForeignKeyConstraint baseColumnNames="APPLICATION_ID" baseTableName="APP_NODE_REGISTRATIONS" constraintName="FK8454723BA992F594" referencedColumnNames="ID" referencedTableName="CLIENT"/>
+        <customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.AddRealmCodeSecret"/>
     </changeSet>
 </databaseChangeLog>
\ No newline at end of file
diff --git a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/updates/Update1_1_0_Beta1.java b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/updates/Update1_1_0_Beta1.java
index 89d372f..f080244 100644
--- a/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/updates/Update1_1_0_Beta1.java
+++ b/connections/mongo/src/main/java/org/keycloak/connections/mongo/updater/updates/Update1_1_0_Beta1.java
@@ -1,5 +1,13 @@
 package org.keycloak.connections.mongo.updater.updates;
 
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.Arrays;
+
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
@@ -14,6 +22,24 @@ public class Update1_1_0_Beta1 extends Update {
     public void update() {
         deleteEntries("clientSessions");
         deleteEntries("sessions");
+
+        addRealmCodeSecret();
+    }
+
+    private void addRealmCodeSecret() {
+        DBCollection realms = db.getCollection("realms");
+
+        DBObject query = new QueryBuilder()
+                .and("codeSecret").is(null).get();
+
+        DBCursor objects = realms.find(query);
+        while (objects.hasNext()) {
+            DBObject object = objects.next();
+            object.put("codeSecret", KeycloakModelUtils.generateCodeSecret());
+            realms.save(object);
+
+            log.debugv("Added realm.codeSecret, id={0}", object.get("id"));
+        }
     }
 
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 3346371..b0a0a21 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -44,6 +44,7 @@ public class RealmRepresentation {
     protected String privateKey;
     protected String publicKey;
     protected String certificate;
+    protected String codeSecret;
     protected RolesRepresentation roles;
     protected List<String> defaultRoles;
     protected Set<String> requiredCredentials;
@@ -229,6 +230,14 @@ public class RealmRepresentation {
         this.certificate = certificate;
     }
 
+    public String getCodeSecret() {
+        return codeSecret;
+    }
+
+    public void setCodeSecret(String codeSecret) {
+        this.codeSecret = codeSecret;
+    }
+
     public Boolean isPasswordCredentialGrantAllowed() {
         return passwordCredentialGrantAllowed;
     }
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 3e1eb51..4fd2de9 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
@@ -50,8 +50,6 @@ public interface LoginFormsProvider extends Provider {
 
     public LoginFormsProvider setClient(ClientModel client);
 
-    LoginFormsProvider setVerifyCode(String code);
-
     public LoginFormsProvider setQueryParams(MultivaluedMap<String, String> queryParams);
 
     public LoginFormsProvider setFormData(MultivaluedMap<String, String> formData);
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 9a76e78..744d588 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
@@ -51,7 +51,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
 
     private static final Logger logger = Logger.getLogger(FreeMarkerLoginFormsProvider.class);
 
-    private String verifyCode;
     private String message;
     private String accessCode;
     private Response.Status status = Response.Status.OK;
@@ -110,8 +109,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
             case VERIFY_EMAIL:
                 try {
                     UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
-                    builder.queryParam("code", accessCode);
-                    builder.queryParam("key", verifyCode);
+                    builder.queryParam("key", accessCode);
 
                     String link = builder.build(realm.getName()).toString();
                     long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
@@ -312,12 +310,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
     }
 
     @Override
-    public LoginFormsProvider setVerifyCode(String code) {
-        this.verifyCode = code;
-        return this;
-    }
-
-    @Override
     public LoginFormsProvider setQueryParams(MultivaluedMap<String, String> queryParams) {
         this.queryParams = queryParams;
         return this;
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 4371e26..ef38009 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
@@ -41,6 +41,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
     private String publicKeyPem;
     private String privateKeyPem;
     private String certificatePem;
+    private String codeSecret;
 
     private String loginTheme;
     private String accountTheme;
@@ -271,6 +272,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
         this.privateKeyPem = privateKeyPem;
     }
 
+    public String getCodeSecret() {
+        return codeSecret;
+    }
+
+    public void setCodeSecret(String codeSecret) {
+        this.codeSecret = codeSecret;
+    }
+
     public String getLoginTheme() {
         return loginTheme;
     }
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 d1895ef..4601fcc 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -97,6 +97,10 @@ public interface RealmModel extends RoleContainerModel {
 
     void setPublicKey(PublicKey publicKey);
 
+    String getCodeSecret();
+
+    void setCodeSecret(String codeSecret);
+
     X509Certificate getCertificate();
     void setCertificate(X509Certificate certificate);
     String getCertificatePem();
diff --git a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index f5a1b3a..09111b4 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -119,6 +119,8 @@ public final class KeycloakModelUtils {
             throw new RuntimeException(e);
         }
         realm.setCertificate(certificate);
+
+        realm.setCodeSecret(generateCodeSecret());
     }
 
     public static void generateRealmCertificate(RealmModel realm) {
@@ -161,6 +163,10 @@ public final class KeycloakModelUtils {
         return secret;
     }
 
+    public static String generateCodeSecret() {
+        return UUID.randomUUID().toString();
+    }
+
     public static ApplicationModel createApplication(RealmModel realm, String name) {
         ApplicationModel app = realm.addApplication(name);
         generateSecret(app);
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 85331ac..7d431c3 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
@@ -91,6 +91,7 @@ public class ModelToRepresentation {
             KeycloakModelUtils.generateRealmCertificate(realm);
         }
         rep.setCertificate(realm.getCertificatePem());
+        rep.setCodeSecret(realm.getCodeSecret());
         rep.setPasswordCredentialGrantAllowed(realm.isPasswordCredentialGrantAllowed());
         rep.setRegistrationAllowed(realm.isRegistrationAllowed());
         rep.setRememberMe(realm.isRememberMe());
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 9610395..5ba8d06 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
@@ -62,7 +62,7 @@ public class RepresentationToModel {
         else newRealm.setAccessTokenLifespan(300);
 
         if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
-        else newRealm.setSsoSessionIdleTimeout(600);
+        else newRealm.setSsoSessionIdleTimeout(1800);
         if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
         else newRealm.setSsoSessionMaxLifespan(36000);
 
@@ -92,6 +92,12 @@ public class RepresentationToModel {
         } else {
             newRealm.setCertificatePem(rep.getCertificate());
         }
+        if (rep.getCodeSecret() == null) {
+            newRealm.setCodeSecret(KeycloakModelUtils.generateCodeSecret());
+        } else {
+            newRealm.setCodeSecret(rep.getCodeSecret());
+        }
+
         if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
         if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
         if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
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 d96a9ea..76c9204 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
@@ -57,6 +57,7 @@ public class CachedRealm {
     private String publicKeyPem;
     private String privateKeyPem;
     private String certificatePem;
+    private String codeSecret;
 
     private String loginTheme;
     private String accountTheme;
@@ -115,6 +116,7 @@ public class CachedRealm {
         publicKeyPem = model.getPublicKeyPem();
         privateKeyPem = model.getPrivateKeyPem();
         certificatePem = model.getCertificatePem();
+        codeSecret = model.getCodeSecret();
 
         loginTheme = model.getLoginTheme();
         accountTheme = model.getAccountTheme();
@@ -267,6 +269,10 @@ public class CachedRealm {
         return privateKeyPem;
     }
 
+    public String getCodeSecret() {
+        return codeSecret;
+    }
+
     public List<RequiredCredentialModel> getRequiredCredentials() {
         return requiredCredentials;
     }
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 d471b4a..eaf9fca 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
@@ -374,7 +374,16 @@ public class RealmAdapter implements RealmModel {
         setPrivateKeyPem(privateKeyPem);
     }
 
+    @Override
+    public String getCodeSecret() {
+        return updated != null ? updated.getCodeSecret() : cached.getCodeSecret();
+    }
 
+    @Override
+    public void setCodeSecret(String codeSecret) {
+        getDelegateForUpdate();
+        updated.setCodeSecret(codeSecret);
+    }
 
     @Override
     public List<RequiredCredentialModel> getRequiredCredentials() {
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 bcb5ad9..c78e916 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
@@ -82,6 +82,8 @@ public class RealmEntity {
     protected String privateKeyPem;
     @Column(name="CERTIFICATE", length = 2048)
     protected String certificatePem;
+    @Column(name="CODE_SECRET", length = 255)
+    protected String codeSecret;
 
     @Column(name="LOGIN_THEME")
     protected String loginTheme;
@@ -284,6 +286,14 @@ public class RealmEntity {
         this.privateKeyPem = privateKeyPem;
     }
 
+    public String getCodeSecret() {
+        return codeSecret;
+    }
+
+    public void setCodeSecret(String codeSecret) {
+        this.codeSecret = codeSecret;
+    }
+
     public Collection<RequiredCredentialEntity> getRequiredCredentials() {
         return requiredCredentials;
     }
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 5578b88..ee97080 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
@@ -434,6 +434,16 @@ public class RealmAdapter implements RealmModel {
         setPrivateKeyPem(privateKeyPem);
     }
 
+    @Override
+    public String getCodeSecret() {
+        return realm.getCodeSecret();
+    }
+
+    @Override
+    public void setCodeSecret(String codeSecret) {
+        realm.setCodeSecret(codeSecret);
+    }
+
     protected RequiredCredentialModel initRequiredCredentialModel(String type) {
         RequiredCredentialModel model = RequiredCredentialModel.BUILT_IN.get(type);
         if (model == null) {
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 ba51c13..5963ab0 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
@@ -420,6 +420,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
+    public String getCodeSecret() {
+        return realm.getCodeSecret();
+    }
+
+    @Override
+    public void setCodeSecret(String codeSecret) {
+        realm.setCodeSecret(codeSecret);
+        updateRealm();
+    }
+
+    @Override
     public String getLoginTheme() {
         return realm.getLoginTheme();
     }
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 1c8c317..5bcbb87 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
@@ -16,6 +16,7 @@ import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.OpenIDConnectService;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
@@ -201,6 +202,7 @@ public class SamlService {
             clientSession.setAuthMethod(SamlProtocol.LOGIN_PROTOCOL);
             clientSession.setRedirectUri(redirect);
             clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
+            clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
             clientSession.setNote(SamlProtocol.SAML_BINDING, getBindingType());
             clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
             clientSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
index 96c3ef6..0c60ccb 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
@@ -550,7 +550,7 @@ public class OpenIDConnectService {
             String[] parts = code.split("\\.");
             if (parts.length == 2) {
                 try {
-                    event.detail(Details.CODE_ID, new String(Base64Url.decode(parts[1])));
+                    event.detail(Details.CODE_ID, new String(parts[1]));
                 } catch (Throwable t) {
                 }
             }
@@ -776,6 +776,7 @@ public class OpenIDConnectService {
             clientSession.setAuthMethod(OpenIDConnect.LOGIN_PROTOCOL);
             clientSession.setRedirectUri(redirect);
             clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
+            clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
             clientSession.setNote(OpenIDConnect.STATE_PARAM, state);
             if (scopeParam != null) clientSession.setNote(OpenIDConnect.SCOPE_PARAM, scopeParam);
             if (responseType != null) clientSession.setNote(OpenIDConnect.RESPONSE_TYPE_PARAM, responseType);
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index cf5978f..655b148 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -49,7 +49,7 @@ public class ApplianceBootstrap {
         realm.setName(adminRealmName);
         realm.setEnabled(true);
         realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
-        realm.setSsoSessionIdleTimeout(300);
+        realm.setSsoSessionIdleTimeout(1800);
         realm.setAccessTokenLifespan(60);
         realm.setSsoSessionMaxLifespan(36000);
         realm.setAccessCodeLifespan(60);
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 9dbfbea..4856c02 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -290,9 +290,6 @@ public class AuthenticationManager {
 
             LoginFormsProvider loginFormsProvider = Flows.forms(session, realm, client, uriInfo).setClientSessionCode(accessCode.getCode()).setUser(user);
             if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL)) {
-                String key = UUID.randomUUID().toString();
-                clientSession.setNote("key", key);
-                loginFormsProvider.setVerifyCode(key);
                 event.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, user.getEmail()).success();
             }
 
diff --git a/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java b/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
index 46bba42..526e791 100755
--- a/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
+++ b/services/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
@@ -1,8 +1,5 @@
 package org.keycloak.services.managers;
 
-import org.keycloak.OAuthErrorException;
-import org.keycloak.jose.jws.Algorithm;
-import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -11,11 +8,10 @@ import org.keycloak.models.UserModel.RequiredAction;
 import org.keycloak.util.Base64Url;
 import org.keycloak.util.Time;
 
-import java.nio.ByteBuffer;
 import java.security.MessageDigest;
-import java.security.Signature;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -23,6 +19,10 @@ import java.util.Set;
  */
 public class ClientSessionCode {
 
+    public static final String ACTION_KEY = "action_key";
+
+    private static final byte[] HASH_SEPERATOR = "//".getBytes();
+
     private final RealmModel realm;
     private final ClientSessionModel clientSession;
 
@@ -34,14 +34,14 @@ public class ClientSessionCode {
     public static ClientSessionCode parse(String code, KeycloakSession session) {
         try {
             String[] parts = code.split("\\.");
-            String id = new String(Base64Url.decode(parts[1]));
+            String id = parts[1];
 
             ClientSessionModel clientSession = session.sessions().getClientSession(id);
             if (clientSession == null) {
                 return null;
             }
 
-            String hash = createSignatureHash(clientSession.getRealm(), clientSession);
+            String hash = createHash(clientSession.getRealm(), clientSession);
             if (!hash.equals(parts[0])) {
                 return null;
             }
@@ -56,14 +56,14 @@ public class ClientSessionCode {
     public static ClientSessionCode parse(String code, KeycloakSession session, RealmModel realm) {
         try {
             String[] parts = code.split("\\.");
-            String id = new String(Base64Url.decode(parts[1]));
+            String id = parts[1];
 
             ClientSessionModel clientSession = session.sessions().getClientSession(realm, id);
             if (clientSession == null) {
                 return null;
             }
 
-            String hash = createSignatureHash(realm, clientSession);
+            String hash = createHash(realm, clientSession);
             if (!hash.equals(parts[0])) {
                 return null;
             }
@@ -111,6 +111,7 @@ public class ClientSessionCode {
 
     public void setAction(ClientSessionModel.Action action) {
         clientSession.setAction(action);
+        clientSession.setNote(ACTION_KEY, UUID.randomUUID().toString());
         clientSession.setTimestamp(Time.currentTime());
     }
 
@@ -138,29 +139,24 @@ public class ClientSessionCode {
     }
 
     private static String generateCode(RealmModel realm, ClientSessionModel clientSession) {
-        String hash = createSignatureHash(realm, clientSession);
+        String hash = createHash(realm, clientSession);
 
         StringBuilder sb = new StringBuilder();
         sb.append(hash);
         sb.append(".");
-        sb.append(Base64Url.encode(clientSession.getId().getBytes()));
+        sb.append(clientSession.getId());
 
         return sb.toString();
     }
 
-    private static String createSignatureHash(RealmModel realm, ClientSessionModel clientSession) {
+    private static String createHash(RealmModel realm, ClientSessionModel clientSession) {
         try {
-            Signature signature = Signature.getInstance(RSAProvider.getJavaAlgorithm(Algorithm.RS256));
-            signature.initSign(realm.getPrivateKey());
-            signature.update(clientSession.getId().getBytes());
-            signature.update(ByteBuffer.allocate(4).putInt(clientSession.getTimestamp()));
-            if (clientSession.getAction() != null) {
-                signature.update(clientSession.getAction().toString().getBytes());
-            }
-            byte[] sign = signature.sign();
-
-            MessageDigest digest = MessageDigest.getInstance("sha-1");
-            digest.update(sign);
+            MessageDigest digest = MessageDigest.getInstance("sha-256");
+            digest.update(realm.getCodeSecret().getBytes());
+            digest.update(HASH_SEPERATOR);
+            digest.update(clientSession.getId().getBytes());
+            digest.update(HASH_SEPERATOR);
+            digest.update(clientSession.getNote(ACTION_KEY).getBytes());
             return Base64Url.encode(digest.digest());
         } catch (Exception e) {
             throw new RuntimeException(e);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 5eff07b..2d91533 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -709,9 +709,6 @@ public class UsersResource {
         try {
             UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
             builder.queryParam("code", accessCode.getCode());
-            String key = UUID.randomUUID().toString();
-            clientSession.setNote("key", key);
-            builder.queryParam("key", key);
 
             String link = builder.build(realm.getName()).toString();
             long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
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 7310d74..56bbd93 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -714,22 +714,17 @@ public class LoginActionsService {
 
     @Path("email-verification")
     @GET
-    public Response emailVerification(@QueryParam("code") String code) {
+    public Response emailVerification(@QueryParam("code") String code, @QueryParam("key") String key) {
         event.event(EventType.VERIFY_EMAIL);
-        if (uriInfo.getQueryParameters().containsKey("key")) {
+        if (key != null) {
             Checks checks = new Checks();
-            if (!checks.check(code, ClientSessionModel.Action.VERIFY_EMAIL)) {
+            if (!checks.check(key, ClientSessionModel.Action.VERIFY_EMAIL)) {
                 return checks.response;
             }
             ClientSessionCode accessCode = checks.clientCode;
             ClientSessionModel clientSession = accessCode.getClientSession();
             UserSessionModel userSession = clientSession.getUserSession();
             UserModel user = userSession.getUser();
-            String key = uriInfo.getQueryParameters().getFirst("key");
-            String keyNote = clientSession.getNote("key");
-            if (key == null || !key.equals(keyNote)) {
-                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Somebody is trying to illegally change your email.");
-            }
             initEvent(clientSession);
             user.setEmailVerified(true);
 
@@ -745,16 +740,11 @@ public class LoginActionsService {
             }
             ClientSessionCode accessCode = checks.clientCode;
             ClientSessionModel clientSession = accessCode.getClientSession();
-            String verifyCode = UUID.randomUUID().toString();
-            clientSession.setNote("key", verifyCode);
             UserSessionModel userSession = clientSession.getUserSession();
-            UserModel user = userSession.getUser();
-
             initEvent(clientSession);
 
             return Flows.forms(session, realm, null, uriInfo)
                     .setClientSessionCode(accessCode.getCode())
-                    .setVerifyCode(verifyCode)
                     .setUser(userSession.getUser())
                     .createResponse(RequiredAction.VERIFY_EMAIL);
         }
@@ -762,22 +752,14 @@ public class LoginActionsService {
 
     @Path("password-reset")
     @GET
-    public Response passwordReset(@QueryParam("code") String code) {
+    public Response passwordReset(@QueryParam("code") String code, @QueryParam("key") String key) {
         event.event(EventType.SEND_RESET_PASSWORD);
-        if (uriInfo.getQueryParameters().containsKey("key")) {
+        if (key != null) {
             Checks checks = new Checks();
-            if (!checks.check(code, ClientSessionModel.Action.UPDATE_PASSWORD)) {
+            if (!checks.check(key, ClientSessionModel.Action.UPDATE_PASSWORD)) {
                 return checks.response;
             }
             ClientSessionCode accessCode = checks.clientCode;
-            ClientSessionModel clientSession = accessCode.getClientSession();
-            UserSessionModel userSession = clientSession.getUserSession();
-            UserModel user = userSession.getUser();
-            String key = uriInfo.getQueryParameters().getFirst("key");
-            String keyNote = clientSession.getNote("key");
-            if (key == null || !key.equals(keyNote)) {
-                return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Somebody is trying to illegally change your password.");
-            }
             return Flows.forms(session, realm, null, uriInfo)
                     .setClientSessionCode(accessCode.getCode())
                     .createResponse(RequiredAction.UPDATE_PASSWORD);
@@ -842,10 +824,7 @@ public class LoginActionsService {
 
             try {
                 UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
-                builder.queryParam("code", accessCode.getCode());
-                String verifyCode = UUID.randomUUID().toString();
-                clientSession.setNote("key", verifyCode);
-                builder.queryParam("key", verifyCode);
+                builder.queryParam("key", accessCode.getCode());
 
                 String link = builder.build(realm.getName()).toString();
                 long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
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 f2b8b26..0f2b13f 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
@@ -122,7 +122,7 @@ public class RequiredActionEmailVerificationTest {
 
         String mailCodeId = sendEvent.getDetails().get(Details.CODE_ID);
 
-        //Assert.assertEquals(mailCodeId, verificationUrl.split("key=")[1]);
+        Assert.assertEquals(mailCodeId, verificationUrl.split("key=")[1].split("\\.")[1]);
 
         driver.navigate().to(verificationUrl.trim());
 
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 fcd51b3..ca4b7ee 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
@@ -139,7 +139,7 @@ public class RefreshTokenTest {
 
         Assert.assertThat(token.getExpiration() - Time.currentTime(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
         int actual = refreshToken.getExpiration() - Time.currentTime();
-        Assert.assertThat(actual, allOf(greaterThanOrEqualTo(559), lessThanOrEqualTo(600)));
+        Assert.assertThat(actual, allOf(greaterThanOrEqualTo(1799), lessThanOrEqualTo(1800)));
 
         Assert.assertEquals(sessionId, refreshToken.getSessionState());
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
index 302fc91..6c104fb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/SamlBindingTest.java
@@ -71,8 +71,7 @@ public class SamlBindingTest {
     @WebResource
     protected LoginPage loginPage;
 
-    @Test
-    @Ignore
+    //@Test
     public void runit() throws Exception {
         Thread.sleep(10000000);
     }