Details
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index 0b11d7e..c9355c8 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -34,6 +34,7 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.AccessCode;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
@@ -245,11 +246,6 @@ public class TokenService {
ClientModel client = authorizeClient(authorizationHeader, form, audit);
- if ( (client instanceof ApplicationModel) && ((ApplicationModel)client).isBearerOnly()) {
- audit.error(Errors.NOT_ALLOWED);
- return createError("not_allowed", "Bearer-only applications are not allowed to invoke grants/access", Response.Status.FORBIDDEN);
- }
-
if (!realm.isEnabled()) {
audit.error(Errors.REALM_DISABLED);
return createError("realm_disabled", "Realm is disabled", Response.Status.UNAUTHORIZED);
@@ -312,6 +308,9 @@ public class TokenService {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Response validateAccessToken(@QueryParam("access_token") String tokenString) {
+ if (!checkSsl()) {
+ return createError("https_required", "HTTPS required", Response.Status.FORBIDDEN);
+ }
audit.event(EventType.VALIDATE_ACCESS_TOKEN);
AccessToken token = null;
try {
@@ -423,7 +422,7 @@ public class TokenService {
final MultivaluedMap<String, String> form) {
logger.info("--> refreshAccessToken");
if (!checkSsl()) {
- throw new NotAcceptableException("HTTPS required");
+ return createError("https_required", "HTTPS required", Response.Status.FORBIDDEN);
}
audit.event(EventType.REFRESH_TOKEN);
@@ -716,7 +715,7 @@ public class TokenService {
logger.debug("accessRequest <---");
if (!checkSsl()) {
- throw new NotAcceptableException("HTTPS required");
+ throw new ForbiddenException("HTTPS required");
}
audit.event(EventType.CODE_TO_TOKEN);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 155acb1..d3bb915 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -29,6 +29,10 @@ import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.Event;
+import org.keycloak.enums.SslRequired;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
@@ -277,13 +281,7 @@ public class AccessTokenTest {
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
{
- String header = BasicAuthHelper.createHeader("test-app", "password");
- Form form = new Form();
- form.param("username", "test-user@localhost")
- .param("password", "password");
- Response response = grantTarget.request()
- .header(HttpHeaders.AUTHORIZATION, header)
- .post(Entity.form(form));
+ Response response = executeGrantAccessTokenRequest(grantTarget);
Assert.assertEquals(200, response.getStatus());
tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
response.close();
@@ -320,5 +318,209 @@ public class AccessTokenTest {
}
+ @Test
+ public void testGrantAccessToken() throws Exception {
+ Client client = ClientBuilder.newClient();
+ UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
+ URI grantUri = TokenService.grantAccessTokenUrl(builder).build("test");
+ WebTarget grantTarget = client.target(grantUri);
+
+ { // test checkSsl
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setSslRequired(SslRequired.ALL);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(403, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setSslRequired(SslRequired.EXTERNAL);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+ { // test null username
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("password", "password");
+ Response response = grantTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ Assert.assertEquals(401, response.getStatus());
+ response.close();
+ }
+
+ { // test no password
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("username", "test-user@localhost");
+ Response response = grantTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ Assert.assertEquals(400, response.getStatus());
+ response.close();
+ }
+
+ { // test bearer-only
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ ApplicationModel clientModel = realm.getApplicationByName("test-app");
+ clientModel.setBearerOnly(true);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(400, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ ApplicationModel clientModel = realm.getApplicationByName("test-app");
+ clientModel.setBearerOnly(false);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+ { // test realm disabled
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setEnabled(false);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(401, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setEnabled(true);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+ { // test application disabled
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ ClientModel clientModel = realm.findClient("test-app");
+ clientModel.setEnabled(false);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(400, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ ClientModel clientModel = realm.findClient("test-app");
+ clientModel.setEnabled(true);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+ { // test user action required
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ UserModel user = session.users().getUserByUsername("test-user@localhost", realm);
+ user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(400, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ UserModel user = session.users().getUserByUsername("test-user@localhost", realm);
+ user.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+ { // test user disabled
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ UserModel user = session.users().getUserByUsername("test-user@localhost", realm);
+ user.setEnabled(false);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(400, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ UserModel user = session.users().getUserByUsername("test-user@localhost", realm);
+ user.setEnabled(true);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+
+ {
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(200, response.getStatus());
+ org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
+ response.close();
+ }
+
+ client.close();
+ events.clear();
+
+ }
+
+ protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("username", "test-user@localhost")
+ .param("password", "password");
+ return grantTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ }
+
}
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 361d0c1..bc1195a 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
@@ -29,8 +29,12 @@ import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.Event;
+import org.keycloak.enums.SslRequired;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.RefreshToken;
@@ -335,6 +339,89 @@ public class RefreshTokenTest {
events.clear();
}
+ @Test
+ public void testCheckSsl() throws Exception {
+ Client client = ClientBuilder.newClient();
+ UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
+ URI grantUri = TokenService.grantAccessTokenUrl(builder).build("test");
+ WebTarget grantTarget = client.target(grantUri);
+ builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
+ URI uri = TokenService.refreshUrl(builder).build("test");
+ WebTarget refreshTarget = client.target(uri);
+
+ String refreshToken = null;
+ {
+ Response response = executeGrantAccessTokenRequest(grantTarget);
+ Assert.assertEquals(200, response.getStatus());
+ org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
+ refreshToken = tokenResponse.getRefreshToken();
+ response.close();
+ }
+
+ {
+ Response response = executeRefreshToken(refreshTarget, refreshToken);
+ Assert.assertEquals(200, response.getStatus());
+ org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
+ refreshToken = tokenResponse.getRefreshToken();
+ response.close();
+ }
+
+ { // test checkSsl
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setSslRequired(SslRequired.ALL);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ Response response = executeRefreshToken(refreshTarget, refreshToken);
+ Assert.assertEquals(403, response.getStatus());
+ response.close();
+
+ {
+ KeycloakSession session = keycloakRule.startSession();
+ RealmModel realm = session.realms().getRealmByName("test");
+ realm.setSslRequired(SslRequired.EXTERNAL);
+ session.getTransaction().commit();
+ session.close();
+ }
+
+ }
+
+ {
+ Response response = executeRefreshToken(refreshTarget, refreshToken);
+ Assert.assertEquals(200, response.getStatus());
+ org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
+ refreshToken = tokenResponse.getRefreshToken();
+ response.close();
+ }
+
+
+ client.close();
+ events.clear();
+
+ }
+
+ protected Response executeRefreshToken(WebTarget refreshTarget, String refreshToken) {
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("refresh_token", refreshToken);
+ return refreshTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ }
+
+ protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("username", "test-user@localhost")
+ .param("password", "password");
+ return grantTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+ }
+
}