keycloak-uncached
Changes
connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java 3(+2 -1)
connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java 39(+39 -0)
forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties 10(+7 -3)
forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js 9(+7 -2)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html 30(+22 -8)
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java 46(+36 -10)
Details
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
index c81b062..1418dc4 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml
@@ -69,11 +69,37 @@
<addUniqueConstraint columnNames="GROUP_ID" constraintName="CON_GROUP_ID_DEF_GROUPS" tableName="REALM_DEFAULT_GROUPS"/>
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_DEFAULT_GROUPS" constraintName="FK_DEF_GROUPS_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="GROUP_ID" baseTableName="REALM_DEFAULT_GROUPS" constraintName="FK_DEF_GROUPS_GROUP" referencedColumnNames="ID" referencedTableName="KEYCLOAK_GROUP"/>
+
<addColumn tableName="CLIENT">
<column name="REGISTRATION_TOKEN" type="VARCHAR(255)"/>
+ <column name="STANDARD_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
+ <constraints nullable="false"/>
+ </column>
+ <column name="IMPLICIT_FLOW_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
+ <constraints nullable="false"/>
+ </column>
+ <column name="DIRECT_ACCESS_GRANTS_ENABLED" type="BOOLEAN" defaultValueBoolean="true">
+ <constraints nullable="false"/>
+ </column>
</addColumn>
+ <update tableName="CLIENT">
+ <column name="STANDARD_FLOW_ENABLED" valueBoolean="false"/>
+ <where>DIRECT_GRANTS_ONLY = :value</where>
+ <whereParams>
+ <param valueBoolean="true" />
+ </whereParams>
+ </update>
+
+ <dropDefaultValue tableName="CLIENT" columnName="DIRECT_GRANTS_ONLY" />
+ <dropColumn tableName="CLIENT" columnName="DIRECT_GRANTS_ONLY"/>
+
<modifyDataType tableName="REALM" columnName="PASSWORD_POLICY" newDataType="VARCHAR(2550)"/>
+ <!-- Sybase specific hacks -->
+ <modifySql dbms="sybase">
+ <regExpReplace replace=".*(SET DEFAULT NULL)" with="SELECT 1" />
+ </modifySql>
+
</changeSet>
</databaseChangeLog>
\ No newline at end of file
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
index fa75d6b..e66e16d 100644
--- a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/DefaultMongoUpdaterProvider.java
@@ -28,7 +28,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
Update1_2_0_Beta1.class,
Update1_2_0_CR1.class,
Update1_3_0.class,
- Update1_4_0.class
+ Update1_4_0.class,
+ Update1_7_0.class
};
@Override
diff --git a/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
new file mode 100644
index 0000000..666a3af
--- /dev/null
+++ b/connections/mongo-update/src/main/java/org/keycloak/connections/mongo/updater/impl/updates/Update1_7_0.java
@@ -0,0 +1,39 @@
+package org.keycloak.connections.mongo.updater.impl.updates;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class Update1_7_0 extends Update {
+
+ @Override
+ public String getId() {
+ return "1.7.0";
+ }
+
+ @Override
+ public void update(KeycloakSession session) throws ClassNotFoundException {
+ DBCollection clients = db.getCollection("clients");
+ DBCursor clientsCursor = clients.find();
+
+ try {
+ while (clientsCursor.hasNext()) {
+ BasicDBObject client = (BasicDBObject) clientsCursor.next();
+
+ boolean directGrantsOnly = client.getBoolean("directGrantsOnly", false);
+ client.append("standardFlowEnabled", !directGrantsOnly);
+ client.append("implicitFlowEnabled", false);
+ client.append("directAccessGrantsEnabled", true);
+ client.removeField("directGrantsOnly");
+
+ clients.save(client);
+ }
+ } finally {
+ clientsCursor.close();
+ }
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index 514c0fb..aef643c 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -26,6 +26,9 @@ public class ClientRepresentation {
protected Integer notBefore;
protected Boolean bearerOnly;
protected Boolean consentRequired;
+ protected Boolean standardFlowEnabled;
+ protected Boolean implicitFlowEnabled;
+ protected Boolean directAccessGrantsEnabled;
protected Boolean serviceAccountsEnabled;
protected Boolean directGrantsOnly;
protected Boolean publicClient;
@@ -181,6 +184,30 @@ public class ClientRepresentation {
this.consentRequired = consentRequired;
}
+ public Boolean isStandardFlowEnabled() {
+ return standardFlowEnabled;
+ }
+
+ public void setStandardFlowEnabled(Boolean standardFlowEnabled) {
+ this.standardFlowEnabled = standardFlowEnabled;
+ }
+
+ public Boolean isImplicitFlowEnabled() {
+ return implicitFlowEnabled;
+ }
+
+ public void setImplicitFlowEnabled(Boolean implicitFlowEnabled) {
+ this.implicitFlowEnabled = implicitFlowEnabled;
+ }
+
+ public Boolean isDirectAccessGrantsEnabled() {
+ return directAccessGrantsEnabled;
+ }
+
+ public void setDirectAccessGrantsEnabled(Boolean directAccessGrantsEnabled) {
+ this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+ }
+
public Boolean isServiceAccountsEnabled() {
return serviceAccountsEnabled;
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index bf1af10..d1764e8 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -169,14 +169,18 @@ client.name.tooltip=Specifies display name of the client. For example 'My Client
client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens.
consent-required=Consent Required
consent-required.tooltip=If enabled users have to consent to client access.
-direct-grants-only=Direct Grants Only
-direct-grants-only.tooltip=When enabled, client can only obtain grants from grant REST API.
client-protocol=Client Protocol
client-protocol.tooltip='OpenID connect' allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server.'SAML' enables web-based authentication and authorization scenarios including cross-domain single sign-on (SSO) and uses security tokens containing assertions to pass information.
access-type=Access Type
access-type.tooltip='Confidential' clients require a secret to initiate login protocol. 'Public' clients do not require a secret. 'Bearer-only' clients are web services that never initiate a login.
+standard-flow-enabled=Standard Flow Enabled
+standard-flow-enabled.tooltip=This enables standard OpenID Connect redirect based authentication with authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Authorization Code Flow' for this client.
+implicit-flow-enabled=Implicit Flow Enabled
+implicit-flow-enabled.tooltip=This enables support for OpenID Connect redirect based authentication without authorization code. In terms of OpenID Connect or OAuth2 specifications, this enables support of 'Implicit Flow' for this client.
+direct-access-grants-enabled=Direct Access Grants Enabled
+direct-access-grants-enabled.tooltip=This enables support for Direct Access Grants, which means that client has access to username/password of user and exchange it directly with Keycloak server for access token. In terms of OAuth2 specification, this enables support of 'Resource Owner Password Credentials Grant' for this client.
service-accounts-enabled=Service Accounts Enabled
-service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client.
+service-accounts-enabled.tooltip=Allows you to authenticate this client to Keycloak and retrieve access token dedicated to this client. In terms of OAuth2 specification, this enables support of 'Client Credentials Grant' for this client.
include-authnstatement=Include AuthnStatement
include-authnstatement.tooltip=Should a statement specifying the method and timestamp be included in login responses?
sign-documents=Sign Documents
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 2f3ef63..11bb11b 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -862,7 +862,12 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
$scope.client = angular.copy(client);
updateProperties();
} else {
- $scope.client = { enabled: true, attributes: {}};
+ $scope.client = {
+ enabled: true,
+ standardFlowEnabled: true,
+ directAccessGrantsEnabled: true,
+ attributes: {}
+ };
$scope.client.attributes['saml_signature_canonicalization_method'] = $scope.canonicalization[0].value;
$scope.client.redirectUris = [];
$scope.accessType = $scope.accessTypes[0];
@@ -1039,7 +1044,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, $route, se
$scope.client.attributes['saml.signature.algorithm'] = $scope.signatureAlgorithm;
$scope.client.attributes['saml_name_id_format'] = $scope.nameIdFormat;
- if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && !$scope.client.directGrantsOnly && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) {
+ if ($scope.client.protocol != 'saml' && !$scope.client.bearerOnly && ($scope.client.standardFlowEnabled || $scope.client.implicitFlowEnabled) && (!$scope.client.redirectUris || $scope.client.redirectUris.length == 0)) {
Notifications.error("You must specify at least one redirect uri");
} else {
if ($scope.create) {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index 443cbe9..eb54741 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -59,13 +59,6 @@
</div>
<kc-tooltip>{{:: 'consent-required.tooltip' | translate}}</kc-tooltip>
</div>
- <div class="form-group clearfix block">
- <label class="col-md-2 control-label" for="directGrantsOnly">{{:: 'direct-grants-only' | translate}}</label>
- <div class="col-sm-6">
- <input ng-model="client.directGrantsOnly" name="directGrantsOnly" id="directGrantsOnly" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
- </div>
- <kc-tooltip>{{:: 'direct-grants-only.tooltip' | translate}}</kc-tooltip>
- </div>
<div class="form-group">
<label class="col-md-2 control-label" for="protocol">{{:: 'client-protocol' | translate}}</label>
<div class="col-sm-6">
@@ -92,6 +85,27 @@
</div>
<kc-tooltip>{{:: 'access-type.tooltip' | translate}}</kc-tooltip>
</div>
+ <div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.bearerOnly">
+ <label class="col-md-2 control-label" for="standardFlowEnabled">{{:: 'standard-flow-enabled' | translate}}</label>
+ <kc-tooltip>{{:: 'standard-flow-enabled.tooltip' | translate}}</kc-tooltip>
+ <div class="col-md-6">
+ <input ng-model="client.standardFlowEnabled" name="standardFlowEnabled" id="standardFlowEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+ </div>
+ </div>
+ <div class="form-group" data-ng-show="protocol == 'openid-connect' && client.publicClient && !client.bearerOnly">
+ <label class="col-md-2 control-label" for="implicitFlowEnabled">{{:: 'implicit-flow-enabled' | translate}}</label>
+ <kc-tooltip>{{:: 'implicit-flow-enabled.tooltip' | translate}}</kc-tooltip>
+ <div class="col-md-6">
+ <input ng-model="client.implicitFlowEnabled" name="implicitFlowEnabled" id="implicitFlowEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+ </div>
+ </div>
+ <div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.bearerOnly">
+ <label class="col-md-2 control-label" for="directAccessGrantsEnabled">{{:: 'direct-access-grants-enabled' | translate}}</label>
+ <kc-tooltip>{{:: 'direct-access-grants-enabled.tooltip' | translate}}</kc-tooltip>
+ <div class="col-md-6">
+ <input ng-model="client.directAccessGrantsEnabled" name="directAccessGrantsEnabled" id="directAccessGrantsEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+ </div>
+ </div>
<div class="form-group" data-ng-show="protocol == 'openid-connect' && !client.publicClient && !client.bearerOnly">
<label class="col-md-2 control-label" for="serviceAccountsEnabled">{{:: 'service-accounts-enabled' | translate}}</label>
<kc-tooltip>{{:: 'service-accounts-enabled.tooltip' | translate}}</kc-tooltip>
@@ -202,7 +216,7 @@
<kc-tooltip>{{:: 'root-url.tooltip' | translate}}</kc-tooltip>
</div>
- <div class="form-group clearfix block" data-ng-hide="client.bearerOnly || client.directGrantsOnly">
+ <div class="form-group clearfix block" data-ng-hide="client.bearerOnly || (!client.standardFlowEnabled && !client.implicitFlowEnabled)">
<label class="col-md-2 control-label" for="newRedirectUri"><span class="required" data-ng-show="protocol != 'saml'">*</span> {{:: 'valid-redirect-uris' | translate}}</label>
<div class="col-sm-6">
diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
index 6885308..21175a0 100644
--- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -176,7 +176,7 @@ failedLogout=Logout failed
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
+standardFlowDisabledMessage=Client is not allowed to initiate browser login because standard flow is disabled for the client.
invalidRedirectUriMessage=Invalid redirect uri
unsupportedNameIdFormatMessage=Unsupported NameIDFormat
invlidRequesterMessage=Invalid requester
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 051493e..492c2e1 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -111,12 +111,18 @@ public interface ClientModel extends RoleContainerModel {
boolean isPublicClient();
void setPublicClient(boolean flag);
- boolean isDirectGrantsOnly();
- void setDirectGrantsOnly(boolean flag);
-
boolean isConsentRequired();
void setConsentRequired(boolean consentRequired);
+ boolean isStandardFlowEnabled();
+ void setStandardFlowEnabled(boolean standardFlowEnabled);
+
+ boolean isImplicitFlowEnabled();
+ void setImplicitFlowEnabled(boolean implicitFlowEnabled);
+
+ boolean isDirectAccessGrantsEnabled();
+ void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled);
+
boolean isServiceAccountsEnabled();
void setServiceAccountsEnabled(boolean serviceAccountsEnabled);
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index d04699f..b5edbaf 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -30,6 +30,9 @@ public class ClientEntity extends AbstractIdentifiableEntity {
private String baseUrl;
private boolean bearerOnly;
private boolean consentRequired;
+ private boolean standardFlowEnabled;
+ private boolean implicitFlowEnabled;
+ private boolean directAccessGrantsEnabled;
private boolean serviceAccountsEnabled;
private boolean directGrantsOnly;
private int nodeReRegistrationTimeout;
@@ -243,6 +246,30 @@ public class ClientEntity extends AbstractIdentifiableEntity {
this.consentRequired = consentRequired;
}
+ public boolean isStandardFlowEnabled() {
+ return standardFlowEnabled;
+ }
+
+ public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+ this.standardFlowEnabled = standardFlowEnabled;
+ }
+
+ public boolean isImplicitFlowEnabled() {
+ return implicitFlowEnabled;
+ }
+
+ public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+ this.implicitFlowEnabled = implicitFlowEnabled;
+ }
+
+ public boolean isDirectAccessGrantsEnabled() {
+ return directAccessGrantsEnabled;
+ }
+
+ public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+ this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+ }
+
public boolean isServiceAccountsEnabled() {
return serviceAccountsEnabled;
}
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 723617b..fd88b26 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
@@ -418,8 +418,10 @@ public class ModelToRepresentation {
rep.setFullScopeAllowed(clientModel.isFullScopeAllowed());
rep.setBearerOnly(clientModel.isBearerOnly());
rep.setConsentRequired(clientModel.isConsentRequired());
+ rep.setStandardFlowEnabled(clientModel.isStandardFlowEnabled());
+ rep.setImplicitFlowEnabled(clientModel.isImplicitFlowEnabled());
+ rep.setDirectAccessGrantsEnabled(clientModel.isDirectAccessGrantsEnabled());
rep.setServiceAccountsEnabled(clientModel.isServiceAccountsEnabled());
- rep.setDirectGrantsOnly(clientModel.isDirectGrantsOnly());
rep.setSurrogateAuthRequired(clientModel.isSurrogateAuthRequired());
rep.setRootUrl(clientModel.getRootUrl());
rep.setBaseUrl(clientModel.getBaseUrl());
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 dd82098..82fd2c7 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
@@ -772,8 +772,17 @@ public class RepresentationToModel {
if (resourceRep.getBaseUrl() != null) client.setBaseUrl(resourceRep.getBaseUrl());
if (resourceRep.isBearerOnly() != null) client.setBearerOnly(resourceRep.isBearerOnly());
if (resourceRep.isConsentRequired() != null) client.setConsentRequired(resourceRep.isConsentRequired());
+ if (resourceRep.isStandardFlowEnabled() != null) client.setStandardFlowEnabled(resourceRep.isStandardFlowEnabled());
+ if (resourceRep.isImplicitFlowEnabled() != null) client.setImplicitFlowEnabled(resourceRep.isImplicitFlowEnabled());
+ if (resourceRep.isDirectAccessGrantsEnabled() != null) client.setDirectAccessGrantsEnabled(resourceRep.isDirectAccessGrantsEnabled());
if (resourceRep.isServiceAccountsEnabled() != null) client.setServiceAccountsEnabled(resourceRep.isServiceAccountsEnabled());
- if (resourceRep.isDirectGrantsOnly() != null) client.setDirectGrantsOnly(resourceRep.isDirectGrantsOnly());
+
+ // Backwards compatibility only
+ if (resourceRep.isDirectGrantsOnly() != null) {
+ logger.warn("Using deprecated 'directGrantsOnly' configuration in JSON representation. It will be removed in future versions");
+ client.setStandardFlowEnabled(!resourceRep.isDirectGrantsOnly());
+ }
+
if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
@@ -869,8 +878,10 @@ public class RepresentationToModel {
if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
if (rep.isConsentRequired() != null) resource.setConsentRequired(rep.isConsentRequired());
+ if (rep.isStandardFlowEnabled() != null) resource.setStandardFlowEnabled(rep.isStandardFlowEnabled());
+ if (rep.isImplicitFlowEnabled() != null) resource.setImplicitFlowEnabled(rep.isImplicitFlowEnabled());
+ if (rep.isDirectAccessGrantsEnabled() != null) resource.setDirectAccessGrantsEnabled(rep.isDirectAccessGrantsEnabled());
if (rep.isServiceAccountsEnabled() != null) resource.setServiceAccountsEnabled(rep.isServiceAccountsEnabled());
- if (rep.isDirectGrantsOnly() != null) resource.setDirectGrantsOnly(rep.isDirectGrantsOnly());
if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
if (rep.isFullScopeAllowed() != null) resource.setFullScopeAllowed(rep.isFullScopeAllowed());
if (rep.isFrontchannelLogout() != null) resource.setFrontchannelLogout(rep.isFrontchannelLogout());
diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index e03452a..20c8725 100755
--- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -163,16 +163,6 @@ public class ClientAdapter implements ClientModel {
}
- public boolean isDirectGrantsOnly() {
- if (updated != null) return updated.isDirectGrantsOnly();
- return cached.isDirectGrantsOnly();
- }
-
- public void setDirectGrantsOnly(boolean flag) {
- getDelegateForUpdate();
- updated.setDirectGrantsOnly(flag);
- }
-
public Set<RoleModel> getScopeMappings() {
if (updated != null) return updated.getScopeMappings();
Set<RoleModel> roles = new HashSet<RoleModel>();
@@ -452,6 +442,42 @@ public class ClientAdapter implements ClientModel {
}
@Override
+ public boolean isStandardFlowEnabled() {
+ if (updated != null) return updated.isStandardFlowEnabled();
+ return cached.isStandardFlowEnabled();
+ }
+
+ @Override
+ public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+ getDelegateForUpdate();
+ updated.setStandardFlowEnabled(standardFlowEnabled);
+ }
+
+ @Override
+ public boolean isImplicitFlowEnabled() {
+ if (updated != null) return updated.isImplicitFlowEnabled();
+ return cached.isImplicitFlowEnabled();
+ }
+
+ @Override
+ public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+ getDelegateForUpdate();
+ updated.setImplicitFlowEnabled(implicitFlowEnabled);
+ }
+
+ @Override
+ public boolean isDirectAccessGrantsEnabled() {
+ if (updated != null) return updated.isDirectAccessGrantsEnabled();
+ return cached.isDirectAccessGrantsEnabled();
+ }
+
+ @Override
+ public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+ getDelegateForUpdate();
+ updated.setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+ }
+
+ @Override
public boolean isServiceAccountsEnabled() {
if (updated != null) return updated.isServiceAccountsEnabled();
return cached.isServiceAccountsEnabled();
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 7c7b97d..a683956 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -36,7 +36,6 @@ public class CachedClient implements Serializable {
private Map<String, String> attributes = new HashMap<String, String>();
private boolean publicClient;
private boolean fullScopeAllowed;
- private boolean directGrantsOnly;
private boolean frontchannelLogout;
private int notBefore;
private Set<String> scope = new HashSet<String>();
@@ -49,6 +48,9 @@ public class CachedClient implements Serializable {
private List<String> defaultRoles = new LinkedList<String>();
private boolean bearerOnly;
private boolean consentRequired;
+ private boolean standardFlowEnabled;
+ private boolean implicitFlowEnabled;
+ private boolean directAccessGrantsEnabled;
private boolean serviceAccountsEnabled;
private Map<String, String> roles = new HashMap<String, String>();
private int nodeReRegistrationTimeout;
@@ -67,7 +69,6 @@ public class CachedClient implements Serializable {
protocol = model.getProtocol();
attributes.putAll(model.getAttributes());
notBefore = model.getNotBefore();
- directGrantsOnly = model.isDirectGrantsOnly();
frontchannelLogout = model.isFrontchannelLogout();
publicClient = model.isPublicClient();
fullScopeAllowed = model.isFullScopeAllowed();
@@ -86,6 +87,9 @@ public class CachedClient implements Serializable {
defaultRoles.addAll(model.getDefaultRoles());
bearerOnly = model.isBearerOnly();
consentRequired = model.isConsentRequired();
+ standardFlowEnabled = model.isStandardFlowEnabled();
+ implicitFlowEnabled = model.isImplicitFlowEnabled();
+ directAccessGrantsEnabled = model.isDirectAccessGrantsEnabled();
serviceAccountsEnabled = model.isServiceAccountsEnabled();
for (RoleModel role : model.getRoles()) {
roles.put(role.getName(), role.getId());
@@ -139,10 +143,6 @@ public class CachedClient implements Serializable {
return publicClient;
}
- public boolean isDirectGrantsOnly() {
- return directGrantsOnly;
- }
-
public int getNotBefore() {
return notBefore;
}
@@ -203,6 +203,18 @@ public class CachedClient implements Serializable {
return consentRequired;
}
+ public boolean isStandardFlowEnabled() {
+ return standardFlowEnabled;
+ }
+
+ public boolean isImplicitFlowEnabled() {
+ return implicitFlowEnabled;
+ }
+
+ public boolean isDirectAccessGrantsEnabled() {
+ return directAccessGrantsEnabled;
+ }
+
public boolean isServiceAccountsEnabled() {
return serviceAccountsEnabled;
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 6cb24f8..f677859 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -499,23 +499,43 @@ public class ClientAdapter implements ClientModel {
}
@Override
- public boolean isServiceAccountsEnabled() {
- return entity.isServiceAccountsEnabled();
+ public boolean isStandardFlowEnabled() {
+ return entity.isStandardFlowEnabled();
}
@Override
- public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
- entity.setServiceAccountsEnabled(serviceAccountsEnabled);
+ public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+ entity.setStandardFlowEnabled(standardFlowEnabled);
+ }
+
+ @Override
+ public boolean isImplicitFlowEnabled() {
+ return entity.isImplicitFlowEnabled();
+ }
+
+ @Override
+ public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+ entity.setImplicitFlowEnabled(implicitFlowEnabled);
}
@Override
- public boolean isDirectGrantsOnly() {
- return entity.isDirectGrantsOnly();
+ public boolean isDirectAccessGrantsEnabled() {
+ return entity.isDirectAccessGrantsEnabled();
}
@Override
- public void setDirectGrantsOnly(boolean flag) {
- entity.setDirectGrantsOnly(flag);
+ public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+ entity.setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+ }
+
+ @Override
+ public boolean isServiceAccountsEnabled() {
+ return entity.isServiceAccountsEnabled();
+ }
+
+ @Override
+ public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+ entity.setServiceAccountsEnabled(serviceAccountsEnabled);
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index 6218e26..1569875 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -95,15 +95,21 @@ public class ClientEntity {
@Column(name="MANAGEMENT_URL")
private String managementUrl;
- @Column(name="DIRECT_GRANTS_ONLY")
- protected boolean directGrantsOnly;
-
@Column(name="BEARER_ONLY")
private boolean bearerOnly;
@Column(name="CONSENT_REQUIRED")
private boolean consentRequired;
+ @Column(name="STANDARD_FLOW_ENABLED")
+ private boolean standardFlowEnabled;
+
+ @Column(name="IMPLICIT_FLOW_ENABLED")
+ private boolean implicitFlowEnabled;
+
+ @Column(name="DIRECT_ACCESS_GRANTS_ENABLED")
+ private boolean directAccessGrantsEnabled;
+
@Column(name="SERVICE_ACCOUNTS_ENABLED")
private boolean serviceAccountsEnabled;
@@ -339,20 +345,36 @@ public class ClientEntity {
this.consentRequired = consentRequired;
}
- public boolean isServiceAccountsEnabled() {
- return serviceAccountsEnabled;
+ public boolean isStandardFlowEnabled() {
+ return standardFlowEnabled;
}
- public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
- this.serviceAccountsEnabled = serviceAccountsEnabled;
+ public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+ this.standardFlowEnabled = standardFlowEnabled;
+ }
+
+ public boolean isImplicitFlowEnabled() {
+ return implicitFlowEnabled;
}
- public boolean isDirectGrantsOnly() {
- return directGrantsOnly;
+ public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+ this.implicitFlowEnabled = implicitFlowEnabled;
}
- public void setDirectGrantsOnly(boolean directGrantsOnly) {
- this.directGrantsOnly = directGrantsOnly;
+ public boolean isDirectAccessGrantsEnabled() {
+ return directAccessGrantsEnabled;
+ }
+
+ public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+ this.directAccessGrantsEnabled = directAccessGrantsEnabled;
+ }
+
+ public boolean isServiceAccountsEnabled() {
+ return serviceAccountsEnabled;
+ }
+
+ public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+ this.serviceAccountsEnabled = serviceAccountsEnabled;
}
public int getNodeReRegistrationTimeout() {
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 acc5182..8c1bb87 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
@@ -715,6 +715,8 @@ public class RealmAdapter implements RealmModel {
entity.setId(id);
entity.setClientId(clientId);
entity.setEnabled(true);
+ entity.setStandardFlowEnabled(true);
+ entity.setDirectAccessGrantsEnabled(true);
entity.setRealm(realm);
realm.getClients().add(entity);
em.persist(entity);
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index fc1f13d..eb6bcd9 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -505,24 +505,46 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
}
@Override
- public boolean isServiceAccountsEnabled() {
- return getMongoEntity().isServiceAccountsEnabled();
+ public boolean isStandardFlowEnabled() {
+ return getMongoEntity().isStandardFlowEnabled();
}
@Override
- public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
- getMongoEntity().setServiceAccountsEnabled(serviceAccountsEnabled);
+ public void setStandardFlowEnabled(boolean standardFlowEnabled) {
+ getMongoEntity().setStandardFlowEnabled(standardFlowEnabled);
+ updateMongoEntity();
+ }
+
+ @Override
+ public boolean isImplicitFlowEnabled() {
+ return getMongoEntity().isImplicitFlowEnabled();
+ }
+
+ @Override
+ public void setImplicitFlowEnabled(boolean implicitFlowEnabled) {
+ getMongoEntity().setImplicitFlowEnabled(implicitFlowEnabled);
updateMongoEntity();
}
@Override
- public boolean isDirectGrantsOnly() {
- return getMongoEntity().isDirectGrantsOnly();
+ public boolean isDirectAccessGrantsEnabled() {
+ return getMongoEntity().isDirectAccessGrantsEnabled();
}
@Override
- public void setDirectGrantsOnly(boolean flag) {
- getMongoEntity().setDirectGrantsOnly(flag);
+ public void setDirectAccessGrantsEnabled(boolean directAccessGrantsEnabled) {
+ getMongoEntity().setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
+ updateMongoEntity();
+ }
+
+ @Override
+ public boolean isServiceAccountsEnabled() {
+ return getMongoEntity().isServiceAccountsEnabled();
+ }
+
+ @Override
+ public void setServiceAccountsEnabled(boolean serviceAccountsEnabled) {
+ getMongoEntity().setServiceAccountsEnabled(serviceAccountsEnabled);
updateMongoEntity();
}
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 d31503c..9f42cb5 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
@@ -799,6 +799,8 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
clientEntity.setClientId(clientId);
clientEntity.setRealmId(getId());
clientEntity.setEnabled(true);
+ clientEntity.setStandardFlowEnabled(true);
+ clientEntity.setDirectAccessGrantsEnabled(true);
getMongoStore().insertEntity(clientEntity, invocationContext);
final ClientModel model = new ClientAdapter(session, this, clientEntity, invocationContext);
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 ff1275a..3402593 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
@@ -142,15 +142,15 @@ public class SamlService extends AuthorizationEndpointBase {
event.error(Errors.CLIENT_DISABLED);
return ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
}
- if ((client instanceof ClientModel) && ((ClientModel) client).isBearerOnly()) {
+ if (client.isBearerOnly()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.BEARER_ONLY);
}
- if (client.isDirectGrantsOnly()) {
+ if (!client.isStandardFlowEnabled()) {
event.event(EventType.LOGIN);
event.error(Errors.NOT_ALLOWED);
- return ErrorPage.error(session, Messages.DIRECT_GRANTS_ONLY);
+ return ErrorPage.error(session, Messages.STANDARD_FLOW_DISABLED);
}
session.getContext().setClient(client);
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 c8d5656..250de12 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -172,9 +172,9 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
throw new ErrorPageException(session, Messages.BEARER_ONLY);
}
- if (client.isDirectGrantsOnly()) {
+ if (!client.isStandardFlowEnabled()) {
event.error(Errors.NOT_ALLOWED);
- throw new ErrorPageException(session, Messages.DIRECT_GRANTS_ONLY);
+ throw new ErrorPageException(session, Messages.STANDARD_FLOW_DISABLED);
}
session.getContext().setClient(client);
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 5f2eeb3..6b22606 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -110,7 +110,7 @@ public class Messages {
public static final String BEARER_ONLY = "bearerOnlyMessage";
- public static final String DIRECT_GRANTS_ONLY = "directGrantsOnlyMessage";
+ public static final String STANDARD_FLOW_DISABLED = "standardFlowDisabledMessage";
public static final String INVALID_REDIRECT_URI = "invalidRedirectUriMessage";
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 b2d14b9..c11286a 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
@@ -327,6 +327,13 @@ public class ImportTest extends AbstractModelTest {
Assert.assertFalse(otherAppAdminConsent.isRoleGranted(application.getRole("app-admin")));
Assert.assertTrue(otherAppAdminConsent.isProtocolMapperGranted(gssCredentialMapper));
+ Assert.assertTrue(application.isStandardFlowEnabled());
+ Assert.assertTrue(application.isImplicitFlowEnabled());
+ Assert.assertTrue(application.isDirectAccessGrantsEnabled());
+ Assert.assertFalse(otherApp.isStandardFlowEnabled());
+ Assert.assertFalse(otherApp.isImplicitFlowEnabled());
+ Assert.assertFalse(otherApp.isDirectAccessGrantsEnabled());
+
// Test service accounts
Assert.assertFalse(application.isServiceAccountsEnabled());
Assert.assertTrue(otherApp.isServiceAccountsEnabled());
diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json
index 68ec4d3..2935ff6 100755
--- a/testsuite/integration/src/test/resources/model/testrealm.json
+++ b/testsuite/integration/src/test/resources/model/testrealm.json
@@ -154,6 +154,7 @@
"clientId": "Application",
"name": "Applicationn",
"enabled": true,
+ "implicitFlowEnabled": true,
"nodeReRegistrationTimeout": 50,
"registeredNodes": {
"node1": 10,
@@ -164,6 +165,8 @@
"clientId": "OtherApp",
"name": "Other Application",
"enabled": true,
+ "standardFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
"serviceAccountsEnabled": true,
"clientAuthenticatorType": "client-jwt",
"protocolMappers" : [