KEYCLOAK-2061 Direct Access Grants disabled by default

This commit is contained in:
mposolda 2015-11-30 15:31:28 +01:00
parent ec327c99f4
commit 5b61a10b55
49 changed files with 195 additions and 26 deletions

View file

@ -90,6 +90,7 @@
<update tableName="CLIENT"> <update tableName="CLIENT">
<column name="STANDARD_FLOW_ENABLED" valueBoolean="false"/> <column name="STANDARD_FLOW_ENABLED" valueBoolean="false"/>
<column name="DIRECT_ACCESS_GRANTS_ENABLED" valueBoolean="true"/>
<where>DIRECT_GRANTS_ONLY = :value</where> <where>DIRECT_GRANTS_ONLY = :value</where>
<whereParams> <whereParams>
<param valueBoolean="true" /> <param valueBoolean="true" />

View file

@ -27,7 +27,7 @@ public class Update1_7_0 extends Update {
boolean directGrantsOnly = client.getBoolean("directGrantsOnly", false); boolean directGrantsOnly = client.getBoolean("directGrantsOnly", false);
client.append("standardFlowEnabled", !directGrantsOnly); client.append("standardFlowEnabled", !directGrantsOnly);
client.append("implicitFlowEnabled", false); client.append("implicitFlowEnabled", false);
client.append("directAccessGrantsEnabled", true); client.append("directAccessGrantsEnabled", directGrantsOnly);
client.removeField("directGrantsOnly"); client.removeField("directGrantsOnly");
clients.save(client); clients.save(client);

View file

@ -82,11 +82,24 @@
<section> <section>
<title>Migrating to 1.7.0.CR1</title> <title>Migrating to 1.7.0.CR1</title>
<simplesect> <simplesect>
<title>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</title> <title>Direct access grants disabled by default for clients</title>
<para> <para>
form-error-page in web.xml will no longer work for client adapter authentication errors. You must define an error-page for In order to add more compliance with OpenID Connect specification, we added flags into admin console to Client Settings page,
the the various HTTP error codes. See documentation for more details if you want to catch and handle adapter error conditions. where you can enable/disable various kinds of OpenID Connect/OAuth2 flows (Standard flow, Implicit flow, Direct Access Grants, Service Accounts).
As part of this, we have <literal>Direct Access Grants</literal> (corresponds to OAuth2 <literal>Resource Owner Password Credentials Grant</literal>) disabled by default for new clients.
</para> </para>
<para>
Clients migrated from previous version have <literal>Direct Access Grants</literal> enabled just if they had flag <literal>Direct Grants Only</literal> on. The
<literal>Direct Grants Only</literal> flag was removed as if you enable Direct Access Grants and disable both Standard+Implicit flow, you will achieve same effect.
</para>
<para>
We also added builtin client <literal>admin-cli</literal> to each realm. This client has <literal>Direct Access Grants</literal> enabled.
So if you're using Admin REST API or Keycloak admin-client, you should update your configuration to use <literal>admin-cli</literal> instead
of <literal>security-admin-console</literal> as the latter one doesn't have direct access grants enabled anymore by default.
</para>
</simplesect>
<simplesect>
<title>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</title>
<para> <para>
In this version, we added <literal>First Broker Login</literal>, which allows you to specify what exactly should be done In this version, we added <literal>First Broker Login</literal>, which allows you to specify what exactly should be done
when new user is logged through Identity provider (or Social provider), but there is no existing Keycloak user when new user is logged through Identity provider (or Social provider), but there is no existing Keycloak user
@ -100,6 +113,13 @@
and then you configure the option under <literal>Review Profile</literal> authenticator. and then you configure the option under <literal>Review Profile</literal> authenticator.
</para> </para>
</simplesect> </simplesect>
<simplesect>
<title>Element 'form-error-page' in web.xml not supported anymore</title>
<para>
form-error-page in web.xml will no longer work for client adapter authentication errors. You must define an error-page for
the various HTTP error codes. See documentation for more details if you want to catch and handle adapter error conditions.
</para>
</simplesect>
</section> </section>
<section> <section>
<title>Migrating to 1.6.0.Final</title> <title>Migrating to 1.6.0.Final</title>

View file

@ -24,6 +24,7 @@
"clients": [ "clients": [
{ {
"clientId": "examples-admin-client", "clientId": "examples-admin-client",
"directAccessGrantsEnabled": true,
"enabled": true, "enabled": true,
"fullScopeAllowed": true, "fullScopeAllowed": true,
"baseUrl": "/examples-admin-client", "baseUrl": "/examples-admin-client",

View file

@ -43,6 +43,7 @@
"clients": [ "clients": [
{ {
"clientId": "basic-auth-service", "clientId": "basic-auth-service",
"directAccessGrantsEnabled": true,
"enabled": true, "enabled": true,
"adminUrl": "/basicauth", "adminUrl": "/basicauth",
"baseUrl": "/basicauth", "baseUrl": "/basicauth",

View file

@ -49,6 +49,7 @@
"enabled": true, "enabled": true,
"fullScopeAllowed": true, "fullScopeAllowed": true,
"baseUrl": "/admin-client", "baseUrl": "/admin-client",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"/admin-client/*" "/admin-client/*"
], ],

View file

@ -178,7 +178,7 @@
"clientId": "admin-client", "clientId": "admin-client",
"enabled": true, "enabled": true,
"publicClient": true, "publicClient": true,
"directGrantsOnly": true "directAccessGrantsEnabled": true
}, },
{ {
"clientId": "product-sa-client", "clientId": "product-sa-client",

View file

@ -182,7 +182,7 @@
"clientId": "ssh-jmx-admin-client", "clientId": "ssh-jmx-admin-client",
"enabled": true, "enabled": true,
"publicClient": false, "publicClient": false,
"directGrantsOnly": true, "directAccessGrantsEnabled": true,
"secret": "password" "secret": "password"
} }
], ],

View file

@ -55,6 +55,7 @@ role_read-token=Read token
role_offline-access=Offline access role_offline-access=Offline access
client_account=Account client_account=Account
client_security-admin-console=Security Admin Console client_security-admin-console=Security Admin Console
client_admin-cli=Admin CLI
client_realm-management=Realm Management client_realm-management=Realm Management
client_broker=Broker client_broker=Broker

View file

@ -113,6 +113,7 @@ role_read-token=Read token
role_offline-access=Offline access role_offline-access=Offline access
client_account=Account client_account=Account
client_security-admin-console=Security Admin Console client_security-admin-console=Security Admin Console
client_admin-cli=Admin CLI
client_realm-management=Realm Management client_realm-management=Realm Management
client_broker=Broker client_broker=Broker

View file

@ -1,6 +1,7 @@
package org.keycloak.migration; package org.keycloak.migration;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@ -21,4 +22,6 @@ public interface MigrationProvider extends Provider {
List<ProtocolMapperModel> getBuiltinMappers(String protocol); List<ProtocolMapperModel> getBuiltinMappers(String protocol);
void setupAdminCli(RealmModel realm);
} }

View file

@ -2,6 +2,7 @@ package org.keycloak.migration.migrators;
import java.util.List; import java.util.List;
import org.keycloak.migration.MigrationProvider;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -18,6 +19,9 @@ public class MigrateTo1_7_0 {
List<RealmModel> realms = session.realms().getRealms(); List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) { for (RealmModel realm : realms) {
realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT); realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT);
MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class);
migrationProvider.setupAdminCli(realm);
} }
} }
} }

View file

@ -8,6 +8,7 @@ import org.keycloak.OAuth2Constants;
*/ */
public interface Constants { public interface Constants {
String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console"; String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
String ADMIN_CLI_CLIENT_ID = "admin-cli";
String ACCOUNT_MANAGEMENT_CLIENT_ID = "account"; String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
String IMPERSONATION_SERVICE_CLIENT_ID = "impersonation"; String IMPERSONATION_SERVICE_CLIENT_ID = "impersonation";

View file

@ -225,6 +225,11 @@ public class TokenEndpoint {
throw new ErrorResponseException("invalid_grant", "Auth error", Response.Status.BAD_REQUEST); throw new ErrorResponseException("invalid_grant", "Auth error", Response.Status.BAD_REQUEST);
} }
if (!client.isStandardFlowEnabled()) {
event.error(Errors.NOT_ALLOWED);
throw new ErrorResponseException("invalid_grant", "Client not allowed to exchange code", Response.Status.BAD_REQUEST);
}
UserModel user = session.users().getUserById(userSession.getUser().getId(), realm); UserModel user = session.users().getUserById(userSession.getUser().getId(), realm);
if (user == null) { if (user == null) {
event.error(Errors.USER_NOT_FOUND); event.error(Errors.USER_NOT_FOUND);
@ -331,6 +336,11 @@ public class TokenEndpoint {
public Response buildResourceOwnerPasswordCredentialsGrant() { public Response buildResourceOwnerPasswordCredentialsGrant() {
event.detail(Details.AUTH_METHOD, "oauth_credentials"); event.detail(Details.AUTH_METHOD, "oauth_credentials");
if (!client.isDirectAccessGrantsEnabled()) {
event.error(Errors.NOT_ALLOWED);
throw new ErrorResponseException("invalid_grant", "Client not allowed for direct access grants", Response.Status.BAD_REQUEST);
}
if (client.isConsentRequired()) { if (client.isConsentRequired()) {
event.error(Errors.CONSENT_DENIED); event.error(Errors.CONSENT_DENIED);
throw new ErrorResponseException("invalid_client", "Client requires user consent", Response.Status.BAD_REQUEST); throw new ErrorResponseException("invalid_client", "Client requires user consent", Response.Status.BAD_REQUEST);

View file

@ -113,6 +113,7 @@ public class RealmManager implements RealmImporter {
setupAccountManagement(realm); setupAccountManagement(realm);
setupBrokerService(realm); setupBrokerService(realm);
setupAdminConsole(realm); setupAdminConsole(realm);
setupAdminCli(realm);
setupImpersonationService(realm); setupImpersonationService(realm);
setupAuthenticationFlows(realm); setupAuthenticationFlows(realm);
setupRequiredActions(realm); setupRequiredActions(realm);
@ -158,6 +159,30 @@ public class RealmManager implements RealmImporter {
adminConsole.addScopeMapping(adminRole); adminConsole.addScopeMapping(adminRole);
} }
public void setupAdminCli(RealmModel realm) {
ClientModel adminCli = realm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
if (adminCli == null) {
adminCli = new ClientManager(this).createClient(realm, Constants.ADMIN_CLI_CLIENT_ID);
adminCli.setName("${client_" + Constants.ADMIN_CLI_CLIENT_ID + "}");
adminCli.setEnabled(true);
adminCli.setPublicClient(true);
adminCli.setFullScopeAllowed(false);
adminCli.setStandardFlowEnabled(false);
adminCli.setDirectAccessGrantsEnabled(true);
RoleModel adminRole;
if (realm.getName().equals(Config.getAdminRealm())) {
adminRole = realm.getRole(AdminRoles.ADMIN);
} else {
String realmAdminApplicationClientId = getRealmAdminClientId(realm);
ClientModel realmAdminApp = realm.getClientByClientId(realmAdminApplicationClientId);
adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
}
adminCli.addScopeMapping(adminRole);
}
}
public String getRealmAdminClientId(RealmModel realm) { public String getRealmAdminClientId(RealmModel realm) {
return Constants.REALM_MANAGEMENT_CLIENT_ID; return Constants.REALM_MANAGEMENT_CLIENT_ID;
} }
@ -375,6 +400,7 @@ public class RealmManager implements RealmImporter {
if (!hasBrokerClient(rep)) setupBrokerService(realm); if (!hasBrokerClient(rep)) setupBrokerService(realm);
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm); if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
if (!hasAdminCliClient(rep)) setupAdminCli(realm);
if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE)) setupOfflineTokens(realm); if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE)) setupOfflineTokens(realm);
RepresentationToModel.importRealm(session, rep, realm); RepresentationToModel.importRealm(session, rep, realm);
@ -428,6 +454,10 @@ public class RealmManager implements RealmImporter {
return hasClient(rep, Constants.ADMIN_CONSOLE_CLIENT_ID); return hasClient(rep, Constants.ADMIN_CONSOLE_CLIENT_ID);
} }
private boolean hasAdminCliClient(RealmRepresentation rep) {
return hasClient(rep, Constants.ADMIN_CLI_CLIENT_ID);
}
private boolean hasClient(RealmRepresentation rep, String clientId) { private boolean hasClient(RealmRepresentation rep, String clientId) {
if (rep.getClients() != null) { if (rep.getClients() != null) {
for (ClientRepresentation clientRep : rep.getClients()) { for (ClientRepresentation clientRep : rep.getClients()) {

View file

@ -10,12 +10,14 @@ import org.keycloak.migration.MigrationProvider;
import org.keycloak.models.ClaimMask; import org.keycloak.models.ClaimMask;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.LoginProtocolFactory;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.services.managers.RealmManager;
/** /**
* Various common utils needed for migration from older version to newer * Various common utils needed for migration from older version to newer
@ -59,6 +61,11 @@ public class DefaultMigrationProvider implements MigrationProvider {
return providerFactory.getBuiltinMappers(); return providerFactory.getBuiltinMappers();
} }
@Override
public void setupAdminCli(RealmModel realm) {
new RealmManager(session).setupAdminCli(realm);
}
@Override @Override
public void close() { public void close() {
} }

View file

@ -183,7 +183,7 @@ public class ContainersTestEnricher {
private void initializeAdminClient() { private void initializeAdminClient() {
adminClient.set(Keycloak.getInstance( adminClient.set(Keycloak.getInstance(
getAuthServerContextRootFromSystemProperty() + "/auth", getAuthServerContextRootFromSystemProperty() + "/auth",
MASTER, ADMIN, ADMIN, Constants.ADMIN_CONSOLE_CLIENT_ID)); MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID));
} }
private void initializeOAuthClient() { private void initializeOAuthClient() {

View file

@ -187,7 +187,7 @@ public class AdapterTestStrategy extends ExternalResource {
Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad")); Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
// View stats // View stats
List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", "security-admin-console").realm("demo").getClientSessionStats(); List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID).realm("demo").getClientSessionStats();
Map<String, String> customerPortalStats = null; Map<String, String> customerPortalStats = null;
Map<String, String> productPortalStats = null; Map<String, String> productPortalStats = null;
for (Map<String, String> s : stats) { for (Map<String, String> s : stats) {
@ -594,7 +594,7 @@ public class AdapterTestStrategy extends ExternalResource {
loginAndCheckSession(driver, loginPage); loginAndCheckSession(driver, loginPage);
// logout mposolda with admin client // logout mposolda with admin client
Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID); Keycloak keycloakAdmin = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
ApiUtil.findClientByClientId(keycloakAdmin.realm("demo"), "session-portal").logoutUser("mposolda"); ApiUtil.findClientByClientId(keycloakAdmin.realm("demo"), "session-portal").logoutUser("mposolda");
// bburke should be still logged with original httpSession in our browser window // bburke should be still logged with original httpSession in our browser window

View file

@ -131,7 +131,7 @@ public class RelativeUriAdapterTest {
Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad")); Assert.assertTrue(pageSource.contains("iPhone") && pageSource.contains("iPad"));
// View stats // View stats
List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", "security-admin-console").realm("demo").getClientSessionStats(); List<Map<String, String>> stats = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID).realm("demo").getClientSessionStats();
Map<String, String> customerPortalStats = null; Map<String, String> customerPortalStats = null;
Map<String, String> productPortalStats = null; Map<String, String> productPortalStats = null;
for (Map<String, String> s : stats) { for (Map<String, String> s : stats) {

View file

@ -43,7 +43,7 @@ public class AddUserTest {
try { try {
server.start(); server.start();
Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "addusertest-admin", "password", Constants.ADMIN_CONSOLE_CLIENT_ID); Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "addusertest-admin", "password", Constants.ADMIN_CLI_CLIENT_ID);
keycloak.realms().findAll(); keycloak.realms().findAll();
RealmRepresentation testRealm = new RealmRepresentation(); RealmRepresentation testRealm = new RealmRepresentation();

View file

@ -45,10 +45,12 @@ public abstract class AbstractClientTest {
testRealm.setEnabled(true); testRealm.setEnabled(true);
testRealm.setAccessCodeLifespanUserAction(600); testRealm.setAccessCodeLifespanUserAction(600);
KeycloakModelUtils.generateRealmKeys(testRealm); KeycloakModelUtils.generateRealmKeys(testRealm);
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
} }
}); });
keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID); keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
realm = keycloak.realm(REALM_NAME); realm = keycloak.realm(REALM_NAME);
} }

View file

@ -79,7 +79,7 @@ public class AdminAPITest {
RealmManager manager = new RealmManager(session); RealmManager manager = new RealmManager(session);
RealmModel adminRealm = manager.getRealm(Config.getAdminRealm()); RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
TokenManager tm = new TokenManager(); TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername("admin", adminRealm); UserModel admin = session.users().getUserByUsername("admin", adminRealm);
ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole); ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);

View file

@ -4,6 +4,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource; import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.models.Constants;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@ -42,7 +43,7 @@ public class ClientTest extends AbstractClientTest {
@Test @Test
public void getClients() { public void getClients() {
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker"); assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID);
} }
private String createClient() { private String createClient() {
@ -60,7 +61,7 @@ public class ClientTest extends AbstractClientTest {
String id = createClient(); String id = createClient();
assertNotNull(realm.clients().get(id)); assertNotNull(realm.clients().get(id));
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app"); assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID);
} }
@Test @Test

View file

@ -117,7 +117,7 @@ public class ImpersonationTest {
RealmManager manager = new RealmManager(session); RealmManager manager = new RealmManager(session);
RealmModel adminRealm = manager.getRealm(realm); RealmModel adminRealm = manager.getRealm(realm);
ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
TokenManager tm = new TokenManager(); TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername(username, adminRealm); UserModel admin = session.users().getUserByUsername(username, adminRealm);
ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole); ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);

View file

@ -77,6 +77,8 @@ public class FederationProvidersIntegrationTest {
ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1"); ldapFedProvider.getLdapIdentityStore().updatePassword(john, "Password1");
LDAPObject existing = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678"); LDAPObject existing = FederationTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678");
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
} }
}); });

View file

@ -77,6 +77,8 @@ public class BruteForceTest {
appRealm.setBruteForceProtected(true); appRealm.setBruteForceProtected(true);
appRealm.setFailureFactor(2); appRealm.setFailureFactor(2);
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
} }
}); });
@ -116,7 +118,7 @@ public class BruteForceTest {
} }
public String getAdminToken() throws Exception { public String getAdminToken() throws Exception {
String clientId = Constants.ADMIN_CONSOLE_CLIENT_ID; String clientId = Constants.ADMIN_CLI_CLIENT_ID;
return oauth.doGrantAccessTokenRequest("master", "admin", "admin", null, clientId, null).getAccessToken(); return oauth.doGrantAccessTokenRequest("master", "admin", "admin", null, clientId, null).getAccessToken();
} }

View file

@ -127,7 +127,11 @@ public class CustomFlowTest {
// Set passthrough clientAuthenticator for our clients // Set passthrough clientAuthenticator for our clients
ClientModel dummyClient = new ClientManager().createClient(appRealm, "dummy-client"); ClientModel dummyClient = new ClientManager().createClient(appRealm, "dummy-client");
dummyClient.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID); dummyClient.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
appRealm.getClientByClientId("test-app").setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID); dummyClient.setDirectAccessGrantsEnabled(true);
ClientModel testApp = appRealm.getClientByClientId("test-app");
testApp.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
testApp.setDirectAccessGrantsEnabled(true);
} }
}); });

View file

@ -48,6 +48,7 @@ public class JaxrsBasicAuthTest {
app.setEnabled(true); app.setEnabled(true);
app.setSecret("password"); app.setSecret("password");
app.setFullScopeAllowed(true); app.setFullScopeAllowed(true);
app.setDirectAccessGrantsEnabled(true);
JaxrsBasicAuthTest.appRealm = appRealm; JaxrsBasicAuthTest.appRealm = appRealm;
} }

View file

@ -456,7 +456,7 @@ public class SamlAdapterTestStrategy extends ExternalResource {
public static void uploadSP(String AUTH_SERVER_URL) { public static void uploadSP(String AUTH_SERVER_URL) {
try { try {
Keycloak keycloak = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID, null); Keycloak keycloak = Keycloak.getInstance(AUTH_SERVER_URL, "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID, null);
RealmResource admin = keycloak.realm("demo"); RealmResource admin = keycloak.realm("demo");
admin.toRepresentation(); admin.toRepresentation();

View file

@ -62,15 +62,19 @@ public class GroupTest {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner"); ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner");
app.setDirectAccessGrantsEnabled(true);
app.setSecret("secret"); app.setSecret("secret");
app = appRealm.getClientByClientId("test-app");
app.setDirectAccessGrantsEnabled(true);
UserModel user = session.users().addUser(appRealm, "direct-login"); UserModel user = session.users().addUser(appRealm, "direct-login");
user.setEmail("direct-login@localhost"); user.setEmail("direct-login@localhost");
user.setEnabled(true); user.setEnabled(true);
session.users().updateCredential(appRealm, user, UserCredentialModel.password("password")); session.users().updateCredential(appRealm, user, UserCredentialModel.password("password"));
keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID); keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
} }
}); });

View file

@ -90,7 +90,7 @@ public class ImportTest extends AbstractModelTest {
Assert.assertEquals(0, session.users().getFederatedIdentities(user, realm).size()); Assert.assertEquals(0, session.users().getFederatedIdentities(user, realm).size());
List<ClientModel> resources = realm.getClients(); List<ClientModel> resources = realm.getClients();
Assert.assertEquals(7, resources.size()); Assert.assertEquals(8, resources.size());
// Test applications imported // Test applications imported
ClientModel application = realm.getClientByClientId("Application"); ClientModel application = realm.getClientByClientId("Application");
@ -101,7 +101,7 @@ public class ImportTest extends AbstractModelTest {
Assert.assertNotNull(otherApp); Assert.assertNotNull(otherApp);
Assert.assertNull(nonExisting); Assert.assertNull(nonExisting);
Map<String, ClientModel> clients = realm.getClientNameMap(); Map<String, ClientModel> clients = realm.getClientNameMap();
Assert.assertEquals(7, clients.size()); Assert.assertEquals(8, clients.size());
Assert.assertTrue(clients.values().contains(application)); Assert.assertTrue(clients.values().contains(application));
Assert.assertTrue(clients.values().contains(otherApp)); Assert.assertTrue(clients.values().contains(otherApp));
Assert.assertTrue(clients.values().contains(accountApp)); Assert.assertTrue(clients.values().contains(accountApp));

View file

@ -92,7 +92,14 @@ import static org.junit.Assert.*;
public class AccessTokenTest { public class AccessTokenTest {
@ClassRule @ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule(); public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
}
});
@Rule @Rule
public WebRule webRule = new WebRule(this); public WebRule webRule = new WebRule(this);

View file

@ -61,6 +61,7 @@ public class ClientAuthSignedJWTTest {
app1.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID); app1.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
ClientModel app2 = appRealm.addClient("client2"); ClientModel app2 = appRealm.addClient("client2");
app2.setDirectAccessGrantsEnabled(true);
new ClientManager(manager).enableServiceAccount(app2); new ClientManager(manager).enableServiceAccount(app2);
app2.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID); app2.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);

View file

@ -67,6 +67,7 @@ public class OfflineTokenTest {
appRealm.setSsoSessionIdleTimeout(30); appRealm.setSsoSessionIdleTimeout(30);
ClientModel app = new ClientManager(manager).createClient(appRealm, "offline-client"); ClientModel app = new ClientManager(manager).createClient(appRealm, "offline-client");
app.setDirectAccessGrantsEnabled(true);
app.setSecret("secret1"); app.setSecret("secret1");
String testAppRedirectUri = appRealm.getClientByClientId("test-app").getRedirectUris().iterator().next(); String testAppRedirectUri = appRealm.getClientByClientId("test-app").getRedirectUris().iterator().next();
offlineClientAppUri = UriUtils.getOrigin(testAppRedirectUri) + "/offline-client"; offlineClientAppUri = UriUtils.getOrigin(testAppRedirectUri) + "/offline-client";

View file

@ -71,7 +71,14 @@ import static org.junit.Assert.assertNull;
public class RefreshTokenTest { public class RefreshTokenTest {
@ClassRule @ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule(); public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
}
});
@Rule @Rule
public WebRule webRule = new WebRule(this); public WebRule webRule = new WebRule(this);

View file

@ -35,9 +35,11 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner"); ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner");
app.setDirectAccessGrantsEnabled(true);
app.setSecret("secret"); app.setSecret("secret");
ClientModel app2 = new ClientManager(manager).createClient(appRealm, "resource-owner-public"); ClientModel app2 = new ClientManager(manager).createClient(appRealm, "resource-owner-public");
app2.setDirectAccessGrantsEnabled(true);
app2.setPublicClient(true); app2.setPublicClient(true);
UserModel user = session.users().addUser(appRealm, "direct-login"); UserModel user = session.users().addUser(appRealm, "direct-login");
@ -191,6 +193,41 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
.assertEvent(); .assertEvent();
} }
@Test
public void grantAccessTokenClientNotAllowed() throws Exception {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel client = appRealm.getClientByClientId("resource-owner");
client.setDirectAccessGrantsEnabled(false);
}
});
oauth.clientId("resource-owner");
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "test-user@localhost", "password");
assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError());
events.expectLogin()
.client("resource-owner")
.session((String) null)
.clearDetails()
.error(Errors.NOT_ALLOWED)
.user((String) null)
.assertEvent();
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
ClientModel client = appRealm.getClientByClientId("resource-owner");
client.setDirectAccessGrantsEnabled(true);
}
});
}
@Test @Test
public void grantAccessTokenVerifyEmail() throws Exception { public void grantAccessTokenVerifyEmail() throws Exception {

View file

@ -30,6 +30,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.UserInfo; import org.keycloak.representations.UserInfo;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule; import org.keycloak.testsuite.rule.WebRule;
@ -56,7 +57,14 @@ import static org.junit.Assert.assertNotNull;
public class UserInfoTest { public class UserInfoTest {
@ClassRule @ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule(); public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
}
});
@Rule @Rule
public WebRule webRule = new WebRule(this); public WebRule webRule = new WebRule(this);

View file

@ -457,7 +457,7 @@ public class SamlBindingTest {
public static void uploadSP() { public static void uploadSP() {
try { try {
Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CONSOLE_CLIENT_ID, null); Keycloak keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID, null);
RealmResource admin = keycloak.realm("demo"); RealmResource admin = keycloak.realm("demo");
admin.toRepresentation(); admin.toRepresentation();

View file

@ -120,6 +120,7 @@
{ {
"name": "customer-portal", "name": "customer-portal",
"enabled": true, "enabled": true,
"directAccessGrantsEnabled": true,
"adminUrl": "http://localhost:8081/customer-portal", "adminUrl": "http://localhost:8081/customer-portal",
"baseUrl": "http://localhost:8081/customer-portal", "baseUrl": "http://localhost:8081/customer-portal",
"redirectUris": [ "redirectUris": [

View file

@ -156,6 +156,7 @@
"name": "Applicationn", "name": "Applicationn",
"enabled": true, "enabled": true,
"implicitFlowEnabled": true, "implicitFlowEnabled": true,
"directAccessGrantsEnabled": true,
"nodeReRegistrationTimeout": 50, "nodeReRegistrationTimeout": 50,
"registeredNodes": { "registeredNodes": {
"node1": 10, "node1": 10,

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -46,6 +46,7 @@
"fullScopeAllowed": true, "fullScopeAllowed": true,
"adminUrl": "http://localhost:8080/customer-portal", "adminUrl": "http://localhost:8080/customer-portal",
"baseUrl": "http://localhost:8080/customer-portal", "baseUrl": "http://localhost:8080/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8080/customer-portal/*" "http://localhost:8080/customer-portal/*"
], ],

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -46,6 +46,7 @@
"fullScopeAllowed": true, "fullScopeAllowed": true,
"adminUrl": "http://localhost:8080/customer-portal", "adminUrl": "http://localhost:8080/customer-portal",
"baseUrl": "http://localhost:8080/customer-portal", "baseUrl": "http://localhost:8080/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8080/customer-portal/*" "http://localhost:8080/customer-portal/*"
], ],

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -75,6 +75,7 @@
"enabled": true, "enabled": true,
"adminUrl": "http://localhost:8082/customer-portal", "adminUrl": "http://localhost:8082/customer-portal",
"baseUrl": "http://localhost:8082/customer-portal", "baseUrl": "http://localhost:8082/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8082/customer-portal/*" "http://localhost:8082/customer-portal/*"
], ],

View file

@ -46,6 +46,7 @@
"fullScopeAllowed": true, "fullScopeAllowed": true,
"adminUrl": "http://localhost:8080/customer-portal", "adminUrl": "http://localhost:8080/customer-portal",
"baseUrl": "http://localhost:8080/customer-portal", "baseUrl": "http://localhost:8080/customer-portal",
"directAccessGrantsEnabled": true,
"redirectUris": [ "redirectUris": [
"http://localhost:8080/customer-portal/*" "http://localhost:8080/customer-portal/*"
], ],