Details
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
index 382be7c..74b9b36 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
@@ -11,13 +11,13 @@
<form class="form-horizontal" name="realmForm" novalidate>
<fieldset class="border-top">
<div class="form-group input-select">
- <label class="col-sm-2 control-label" for="tokenLifespan">Token lifespan</label>
+ <label class="col-sm-2 control-label" for="accessTokenLifespan">Access Token lifespan</label>
<div class="col-sm-10">
<div class="row">
<div class="col-sm-2">
<input class="form-control" type="number" required min="1"
- max="31536000" data-ng-model="realm.tokenLifespan"
- id="tokenLifespan" name="tokenLifespan"/>
+ max="31536000" data-ng-model="realm.accessTokenLifespan"
+ id="accessTokenLifespan" name="accessTokenLifespan"/>
</div>
<div class="col-sm-2 select-kc">
<select name="tokenLifespanUnit" data-ng-model="realm.tokenLifespanUnit" >
diff --git a/core/src/main/java/org/keycloak/representations/AccessToken.java b/core/src/main/java/org/keycloak/representations/AccessToken.java
index fd93257..8341c57 100755
--- a/core/src/main/java/org/keycloak/representations/AccessToken.java
+++ b/core/src/main/java/org/keycloak/representations/AccessToken.java
@@ -19,6 +19,19 @@ public class AccessToken extends JsonWebToken {
@JsonProperty("verify_caller")
protected Boolean verifyCaller;
+ public Access() {
+ }
+
+ public Access clone() {
+ Access access = new Access();
+ access.verifyCaller = verifyCaller;
+ if (roles != null) {
+ access.roles = new HashSet<String>();
+ access.roles.addAll(roles);
+ }
+ return access;
+ }
+
public Set<String> getRoles() {
return roles;
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
index 904b692..4f1f2ea 100755
--- a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java
@@ -29,9 +29,6 @@ public class PublishedRealmRepresentation {
@JsonProperty("grants")
protected String grantUrl;
- @JsonProperty("identity-grants")
- protected String identityGrantUrl;
-
@JsonProperty("admin-role")
protected String adminRole;
@@ -124,12 +121,4 @@ public class PublishedRealmRepresentation {
public void setGrantUrl(String grantUrl) {
this.grantUrl = grantUrl;
}
-
- public String getIdentityGrantUrl() {
- return identityGrantUrl;
- }
-
- public void setIdentityGrantUrl(String identityGrantUrl) {
- this.identityGrantUrl = identityGrantUrl;
- }
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index e11dc57..e4d70bb 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -13,7 +13,7 @@ public class RealmRepresentation {
protected String self; // link
protected String id;
protected String realm;
- protected Integer tokenLifespan;
+ protected Integer accessTokenLifespan;
protected Integer accessCodeLifespan;
protected Integer accessCodeLifespanUserAction;
protected Boolean enabled;
@@ -114,12 +114,12 @@ public class RealmRepresentation {
this.sslNotRequired = sslNotRequired;
}
- public Integer getTokenLifespan() {
- return tokenLifespan;
+ public Integer getAccessTokenLifespan() {
+ return accessTokenLifespan;
}
- public void setTokenLifespan(Integer tokenLifespan) {
- this.tokenLifespan = tokenLifespan;
+ public void setAccessTokenLifespan(Integer accessTokenLifespan) {
+ this.accessTokenLifespan = accessTokenLifespan;
}
public List<UserRoleMappingRepresentation> getRoleMappings() {
diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java
new file mode 100755
index 0000000..7d90931
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java
@@ -0,0 +1,36 @@
+package org.keycloak.representations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RefreshToken extends AccessToken {
+ public RefreshToken() {
+ type("REFRESH");
+ }
+
+ /**
+ * Deep copies issuer, subject, issuedFor, realmAccess, and resourceAccess
+ * from AccessToken.
+ *
+ * @param token
+ */
+ public RefreshToken(AccessToken token) {
+ this();
+ this.issuer = token.issuer;
+ this.subject = token.subject;
+ this.issuedFor = token.issuedFor;
+ if (token.realmAccess != null) {
+ realmAccess = token.realmAccess.clone();
+ }
+ if (token.resourceAccess != null) {
+ resourceAccess = new HashMap<String, Access>();
+ for (Map.Entry<String, Access> entry : token.resourceAccess.entrySet()) {
+ resourceAccess.put(entry.getKey(), entry.getValue().clone());
+ }
+ }
+ }
+}
diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json
index 1183de8..9f0fb13 100755
--- a/examples/demo-template/testrealm.json
+++ b/examples/demo-template/testrealm.json
@@ -1,7 +1,7 @@
{
"realm": "demo",
"enabled": true,
- "tokenLifespan": 3000,
+ "accessTokenLifespan": 3000,
"accessCodeLifespan": 10,
"accessCodeLifespanUserAction": 6000,
"sslNotRequired": true,
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 6f22121..a0aad37 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -38,9 +38,13 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
void setResetPasswordAllowed(boolean resetPasswordAllowed);
- int getTokenLifespan();
+ int getAccessTokenLifespan();
- void setTokenLifespan(int tokenLifespan);
+ void setAccessTokenLifespan(int tokenLifespan);
+
+ int getRefreshTokenLifespan();
+
+ void setRefreshTokenLifespan(int tokenLifespan);
int getAccessCodeLifespan();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index e6967e3..d744bff 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -43,9 +43,10 @@ public class RealmEntity {
protected boolean updateProfileOnInitialSocialLogin;
protected String passwordPolicy;
- protected int tokenLifespan;
+ protected int accessTokenLifespan;
protected int accessCodeLifespan;
protected int accessCodeLifespanUserAction;
+ protected int refreshTokenLifespan;
@Column(length = 2048)
protected String publicKeyPem;
@@ -161,12 +162,20 @@ public class RealmEntity {
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
}
- public int getTokenLifespan() {
- return tokenLifespan;
+ public int getRefreshTokenLifespan() {
+ return refreshTokenLifespan;
}
- public void setTokenLifespan(int tokenLifespan) {
- this.tokenLifespan = tokenLifespan;
+ public void setRefreshTokenLifespan(int refreshTokenLifespan) {
+ this.refreshTokenLifespan = refreshTokenLifespan;
+ }
+
+ public int getAccessTokenLifespan() {
+ return accessTokenLifespan;
+ }
+
+ public void setAccessTokenLifespan(int accessTokenLifespan) {
+ this.accessTokenLifespan = accessTokenLifespan;
}
public int getAccessCodeLifespan() {
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 a4a6cb7..608788e 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
@@ -128,13 +128,24 @@ public class RealmAdapter implements RealmModel {
}
@Override
- public int getTokenLifespan() {
- return realm.getTokenLifespan();
+ public int getAccessTokenLifespan() {
+ return realm.getAccessTokenLifespan();
}
@Override
- public void setTokenLifespan(int tokenLifespan) {
- realm.setTokenLifespan(tokenLifespan);
+ public void setAccessTokenLifespan(int tokenLifespan) {
+ realm.setAccessTokenLifespan(tokenLifespan);
+ em.flush();
+ }
+
+ @Override
+ public int getRefreshTokenLifespan() {
+ return realm.getRefreshTokenLifespan();
+ }
+
+ @Override
+ public void setRefreshTokenLifespan(int tokenLifespan) {
+ realm.setRefreshTokenLifespan(tokenLifespan);
em.flush();
}
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 91aa0bf..06991cc 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
@@ -167,13 +167,24 @@ public class RealmAdapter extends AbstractAdapter implements RealmModel {
}
@Override
- public int getTokenLifespan() {
- return realm.getTokenLifespan();
+ public int getAccessTokenLifespan() {
+ return realm.getAccessTokenLifespan();
}
@Override
- public void setTokenLifespan(int tokenLifespan) {
- realm.setTokenLifespan(tokenLifespan);
+ public void setAccessTokenLifespan(int tokenLifespan) {
+ realm.setAccessTokenLifespan(tokenLifespan);
+ updateRealm();
+ }
+
+ @Override
+ public int getRefreshTokenLifespan() {
+ return realm.getRefreshTokenLifespan();
+ }
+
+ @Override
+ public void setRefreshTokenLifespan(int tokenLifespan) {
+ realm.setRefreshTokenLifespan(tokenLifespan);
updateRealm();
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java
index 6ee2fdf..57fe31e 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/RealmEntity.java
@@ -29,9 +29,10 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong
private boolean updateProfileOnInitialSocialLogin;
private String passwordPolicy;
- private int tokenLifespan;
+ private int accessTokenLifespan;
private int accessCodeLifespan;
private int accessCodeLifespanUserAction;
+ private int refreshTokenLifespan;
private String publicKeyPem;
private String privateKeyPem;
@@ -131,12 +132,21 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong
}
@MongoField
- public int getTokenLifespan() {
- return tokenLifespan;
+ public int getAccessTokenLifespan() {
+ return accessTokenLifespan;
}
- public void setTokenLifespan(int tokenLifespan) {
- this.tokenLifespan = tokenLifespan;
+ public void setAccessTokenLifespan(int accessTokenLifespan) {
+ this.accessTokenLifespan = accessTokenLifespan;
+ }
+
+ @MongoField
+ public int getRefreshTokenLifespan() {
+ return refreshTokenLifespan;
+ }
+
+ public void setRefreshTokenLifespan(int refreshTokenLifespan) {
+ this.refreshTokenLifespan = refreshTokenLifespan;
}
@MongoField
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
index cd18852..ea6fa66 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
@@ -47,7 +47,7 @@ public class AdapterTest extends AbstractModelTest {
realmModel.setName("JUGGLER");
realmModel.setPrivateKeyPem("0234234");
realmModel.setPublicKeyPem("0234234");
- realmModel.setTokenLifespan(1000);
+ realmModel.setAccessTokenLifespan(1000);
realmModel.setUpdateProfileOnInitialSocialLogin(true);
realmModel.addDefaultRole("foo");
@@ -56,7 +56,7 @@ public class AdapterTest extends AbstractModelTest {
Assert.assertNotNull(realmModel);
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
- Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
+ Assert.assertEquals(realmModel.getAccessTokenLifespan(), 1000);
Assert.assertEquals(realmModel.isEnabled(), true);
Assert.assertEquals(realmModel.getName(), "JUGGLER");
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
@@ -75,7 +75,7 @@ public class AdapterTest extends AbstractModelTest {
realmModel.setName("JUGGLER");
realmModel.setPrivateKeyPem("0234234");
realmModel.setPublicKeyPem("0234234");
- realmModel.setTokenLifespan(1000);
+ realmModel.setAccessTokenLifespan(1000);
realmModel.setUpdateProfileOnInitialSocialLogin(true);
realmModel.addDefaultRole("foo");
@@ -84,7 +84,7 @@ public class AdapterTest extends AbstractModelTest {
Assert.assertNotNull(realmModel);
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
- Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
+ Assert.assertEquals(realmModel.getAccessTokenLifespan(), 1000);
Assert.assertEquals(realmModel.isEnabled(), true);
Assert.assertEquals(realmModel.getName(), "JUGGLER");
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
index 324802b..c4d316c 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
@@ -127,7 +127,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
realm.setName("Test");
realm.setPrivateKeyPem("0234234");
realm.setPublicKeyPem("0234234");
- realm.setTokenLifespan(1000);
+ realm.setAccessTokenLifespan(1000);
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
am = new AuthenticationManager();
diff --git a/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
index bdc7d3b..33e8490 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/ModelTest.java
@@ -22,7 +22,7 @@ public class ModelTest extends AbstractModelTest {
realm.setSocial(true);
realm.setSslNotRequired(true);
realm.setVerifyEmail(true);
- realm.setTokenLifespan(1000);
+ realm.setAccessTokenLifespan(1000);
realm.setPasswordPolicy(new PasswordPolicy("length"));
realm.setAccessCodeLifespan(1001);
realm.setAccessCodeLifespanUserAction(1002);
@@ -55,7 +55,7 @@ public class ModelTest extends AbstractModelTest {
Assert.assertEquals(expected.isSocial(), actual.isSocial());
Assert.assertEquals(expected.isSslNotRequired(), actual.isSslNotRequired());
Assert.assertEquals(expected.isVerifyEmail(), actual.isVerifyEmail());
- Assert.assertEquals(expected.getTokenLifespan(), actual.getTokenLifespan());
+ Assert.assertEquals(expected.getAccessTokenLifespan(), actual.getAccessTokenLifespan());
Assert.assertEquals(expected.getAccessCodeLifespan(), actual.getAccessCodeLifespan());
Assert.assertEquals(expected.getAccessCodeLifespanUserAction(), actual.getAccessCodeLifespanUserAction());
diff --git a/model/tests/src/test/resources/testcomposites.json b/model/tests/src/test/resources/testcomposites.json
index 2ac02ce..6c11b4e 100755
--- a/model/tests/src/test/resources/testcomposites.json
+++ b/model/tests/src/test/resources/testcomposites.json
@@ -2,7 +2,7 @@
"id": "Test",
"realm": "Test",
"enabled": true,
- "tokenLifespan": 600,
+ "accessTokenLifespan": 600,
"accessCodeLifespan": 600,
"accessCodeLifespanUserAction": 600,
"sslNotRequired": true,
diff --git a/model/tests/src/test/resources/testrealm.json b/model/tests/src/test/resources/testrealm.json
index a78c234..e1148da 100755
--- a/model/tests/src/test/resources/testrealm.json
+++ b/model/tests/src/test/resources/testrealm.json
@@ -1,7 +1,7 @@
{
"realm": "test-realm",
"enabled": true,
- "tokenLifespan": 6000,
+ "accessTokenLifespan": 6000,
"accessCodeLifespan": 30,
"accessCodeLifespanUserAction": 600,
"requiredCredentials": [ "password" ],
diff --git a/model/tests/src/test/resources/testrealm-demo.json b/model/tests/src/test/resources/testrealm-demo.json
index 7cf1072..136a144 100755
--- a/model/tests/src/test/resources/testrealm-demo.json
+++ b/model/tests/src/test/resources/testrealm-demo.json
@@ -1,7 +1,7 @@
{
"realm": "demo",
"enabled": true,
- "tokenLifespan": 300,
+ "accessTokenLifespan": 300,
"accessCodeLifespan": 10,
"accessCodeLifespanUserAction": 600,
"sslNotRequired": true,
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index f4ea7df..93a8e47 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -11,8 +11,6 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
-import java.util.UUID;
-
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -48,7 +46,7 @@ public class ApplianceBootstrap {
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
realm.addRequiredOAuthClientCredential(CredentialRepresentation.PASSWORD);
realm.addRequiredResourceCredential(CredentialRepresentation.PASSWORD);
- realm.setTokenLifespan(300);
+ realm.setAccessTokenLifespan(300);
realm.setAccessCodeLifespan(60);
realm.setAccessCodeLifespanUserAction(300);
realm.setSslNotRequired(true);
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 7d48d3e..14adb6b 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -46,8 +46,8 @@ public class AuthenticationManager {
token.issuedNow();
token.subject(user.getId());
token.audience(realm.getName());
- if (realm.getTokenLifespan() > 0) {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ if (realm.getAccessTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
}
return token;
}
diff --git a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
index d2bacba..c9e921b 100755
--- a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
+++ b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
@@ -71,7 +71,7 @@ public class ModelToRepresentation {
rep.setRegistrationAllowed(realm.isRegistrationAllowed());
rep.setVerifyEmail(realm.isVerifyEmail());
rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
- rep.setTokenLifespan(realm.getTokenLifespan());
+ rep.setAccessTokenLifespan(realm.getAccessTokenLifespan());
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
rep.setSmtpServer(realm.getSmtpConfig());
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 5cc26ce..4148ca0 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -7,7 +7,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
@@ -28,14 +27,10 @@ import org.keycloak.representations.idm.UserRoleMappingRepresentation;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicLong;
/**
* Per request object
@@ -110,7 +105,7 @@ public class RealmManager {
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
if (rep.getAccessCodeLifespanUserAction() != null)
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
- if (rep.getTokenLifespan() != null) realm.setTokenLifespan(rep.getTokenLifespan());
+ if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
if (rep.getRequiredCredentials() != null) {
realm.updateRequiredCredentials(rep.getRequiredCredentials());
}
@@ -163,8 +158,8 @@ public class RealmManager {
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
- if (rep.getTokenLifespan() != null) newRealm.setTokenLifespan(rep.getTokenLifespan());
- else newRealm.setTokenLifespan(300);
+ if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
+ else newRealm.setAccessTokenLifespan(300);
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
else newRealm.setAccessCodeLifespan(60);
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index f6555a0..74b5bd4 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -12,10 +12,12 @@ import org.keycloak.representations.AccessToken;
import org.keycloak.util.Base64Url;
import org.keycloak.util.JsonSerialization;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -78,12 +80,44 @@ public class TokenManager {
public AccessCodeEntry createAccessCode(String scopeParam, String state, String redirect, RealmModel realm, UserModel client, UserModel user) {
+ AccessCodeEntry code = createAccessCodeEntry(scopeParam, state, redirect, realm, client, user);
+ accessCodeMap.put(code.getId(), code);
+ return code;
+ }
+
+ private AccessCodeEntry createAccessCodeEntry(String scopeParam, String state, String redirect, RealmModel realm, UserModel client, UserModel user) {
AccessCodeEntry code = new AccessCodeEntry();
- AccessScope scopeMap = null;
- if (scopeParam != null) scopeMap = decodeScope(scopeParam);
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
+ AccessToken token = createClientAccessToken(scopeParam, realm, client, user, realmRolesRequested, resourceRolesRequested);
+
+ code.setToken(token);
+ code.setRealm(realm);
+ code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
+ code.setClient(client);
+ code.setUser(user);
+ code.setState(state);
+ code.setRedirectUri(redirect);
+ String accessCode = null;
+ try {
+ accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ code.setCode(accessCode);
+ return code;
+ }
+
+ public AccessToken createClientAccessToken(String scopeParam, RealmModel realm, UserModel client, UserModel user) {
+ return createClientAccessToken(scopeParam, realm, client, user, new LinkedList<RoleModel>(), new MultivaluedHashMap<String, RoleModel>());
+ }
+
+
+ public AccessToken createClientAccessToken(String scopeParam, RealmModel realm, UserModel client, UserModel user, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested) {
+ AccessScope scopeMap = null;
+ if (scopeParam != null) scopeMap = decodeScope(scopeParam);
+
Set<RoleModel> roleMappings = realm.getRoleMappings(user);
Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
@@ -113,22 +147,22 @@ public class TokenManager {
}
}
- createToken(code, realm, client, user);
- code.setRealm(realm);
- code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
- code.setClient(client);
- code.setUser(user);
- code.setState(state);
- code.setRedirectUri(redirect);
- accessCodeMap.put(code.getId(), code);
- String accessCode = null;
- try {
- accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
+ AccessToken token = initToken(realm, client, user);
+
+ if (realmRolesRequested.size() > 0) {
+ for (RoleModel role : realmRolesRequested) {
+ addComposites(token, role);
+ }
}
- code.setCode(accessCode);
- return code;
+
+ if (resourceRolesRequested.size() > 0) {
+ for (List<RoleModel> roles : resourceRolesRequested.values()) {
+ for (RoleModel role : roles) {
+ addComposites(token, role);
+ }
+ }
+ }
+ return token;
}
protected AccessToken initToken(RealmModel realm, UserModel client, UserModel user) {
@@ -138,8 +172,8 @@ public class TokenManager {
token.audience(realm.getName());
token.issuedNow();
token.issuedFor(client.getLoginName());
- if (realm.getTokenLifespan() > 0) {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ if (realm.getAccessTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
}
Set<String> allowedOrigins = client.getWebOrigins();
if (allowedOrigins != null) {
@@ -176,26 +210,6 @@ public class TokenManager {
}
- protected void createToken(AccessCodeEntry accessCodeEntry, RealmModel realm, UserModel client, UserModel user) {
-
- AccessToken token = initToken(realm, client, user);
-
- if (accessCodeEntry.getRealmRolesRequested().size() > 0) {
- for (RoleModel role : accessCodeEntry.getRealmRolesRequested()) {
- addComposites(token, role);
- }
- }
-
- if (accessCodeEntry.getResourceRolesRequested().size() > 0) {
- for (List<RoleModel> roles : accessCodeEntry.getResourceRolesRequested().values()) {
- for (RoleModel role : roles) {
- addComposites(token, role);
- }
- }
- }
- accessCodeEntry.setToken(token);
- }
-
public String encodeScope(AccessScope scope) {
String token = null;
try {
@@ -224,8 +238,8 @@ public class TokenManager {
token.issuedNow();
token.subject(user.getId());
token.audience(realm.getName());
- if (realm.getTokenLifespan() > 0) {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ if (realm.getAccessTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
}
for (RoleModel role : realm.getRoleMappings(user)) {
addComposites(token, role);
diff --git a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
index 1b699aa..944f1a9 100755
--- a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java
@@ -53,13 +53,11 @@ public class PublicRealmResource {
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString();
String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString();
String grantUrl = TokenService.grantAccessTokenUrl(uriInfo).build(realm.getName()).toString();
- String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getName()).toString();
html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
html.append("<p>auth: ").append(authUri).append("</p>");
html.append("<p>code: ").append(codeUri).append("</p>");
html.append("<p>grant: ").append(grantUrl).append("</p>");
- html.append("<p>identity grant: ").append(idGrantUrl).append("</p>");
html.append("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>");
html.append("</body></html>");
@@ -77,8 +75,6 @@ public class PublicRealmResource {
rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString());
rep.setCodeUrl(TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString());
rep.setGrantUrl(TokenService.grantAccessTokenUrl(uriInfo).build(realm.getName()).toString());
- String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getName()).toString();
- rep.setIdentityGrantUrl(idGrantUrl);
return rep;
}
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 cf86534..f38c985 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -29,6 +29,7 @@ import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.validation.Validation;
import org.keycloak.util.BasicAuthHelper;
+import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
@@ -108,11 +109,6 @@ public class TokenService {
}
- public static UriBuilder grantIdentityTokenUrl(UriInfo uriInfo) {
- return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "grantIdentityToken");
-
- }
-
public static UriBuilder loginPageUrl(UriInfo uriInfo) {
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "loginPage");
}
@@ -129,44 +125,18 @@ public class TokenService {
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
}
- @Path("grants/identity-token")
+ @Path("grants/access")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
- public Response grantIdentityToken(final MultivaluedMap<String, String> form) {
+ public Response grantAccessToken(final @HeaderParam(HttpHeaders.AUTHORIZATION) String authorizationHeader,
+ final MultivaluedMap<String, String> form) {
if (!checkSsl()) {
throw new NotAcceptableException("HTTPS required");
}
- String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
- if (username == null) {
- throw new NotAuthorizedException("No user");
- }
- if (!realm.isEnabled()) {
- throw new NotAuthorizedException("Disabled realm");
- }
- UserModel user = realm.getUser(username);
-
- AuthenticationStatus status = authManager.authenticateForm(realm, user, form);
- if (status != AuthenticationStatus.SUCCESS) {
- throw new NotAuthorizedException(status);
- }
-
- tokenManager = new TokenManager();
- AccessToken token = authManager.createIdentityToken(realm, user);
- String encoded = tokenManager.encodeToken(realm, token);
- AccessTokenResponse res = accessTokenResponse(token, encoded);
- return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
- }
+ UserModel client = authorizeClient(authorizationHeader);
- @Path("grants/access")
- @POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON)
- public Response grantAccessToken(final MultivaluedMap<String, String> form) {
- if (!checkSsl()) {
- throw new NotAcceptableException("HTTPS required");
- }
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) {
@@ -185,7 +155,8 @@ public class TokenService {
if (authManager.authenticateForm(realm, user, form) != AuthenticationStatus.SUCCESS) {
throw new NotAuthorizedException("Auth failed");
}
- AccessToken token = tokenManager.createAccessToken(realm, user);
+ String scope = form.getFirst("scope");
+ AccessToken token = tokenManager.createClientAccessToken(scope, realm, client, user);
String encoded = tokenManager.encodeToken(realm, token);
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
@@ -341,47 +312,14 @@ public class TokenService {
throw new NotAuthorizedException("Realm not enabled");
}
- if (authorizationHeader == null) {
- throw new NotAuthorizedException("No Authorization header to authenticate client", "Basic realm=\"" + realm.getName() + "\"");
- }
-
- String[] usernameSecret = BasicAuthHelper.parseHeader(authorizationHeader);
- if (usernameSecret == null) {
- throw new NotAuthorizedException("No Authorization header to authenticate client", "Basic realm=\"" + realm.getName() + "\"");
- }
-
- String client_id = usernameSecret[0];
- String clientSecret = usernameSecret[1];
- UserModel client = realm.getUser(client_id);
- if (client == null) {
- logger.debug("Could not find user");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_client");
- error.put("error_description", "Could not find user");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
-
- if (!client.isEnabled()) {
- logger.debug("user is not enabled");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_client");
- error.put("error_description", "User is not enabled");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
-
- if (!realm.validateSecret(client, clientSecret)) {
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "unauthorized_client");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
+ UserModel client = authorizeClient(authorizationHeader);
String code = formData.getFirst("code");
if (code == null) {
- logger.debug("code not specified");
Map<String, String> error = new HashMap<String, String>();
error.put("error", "invalid_request");
error.put("error_description", "code not specified");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+ throw new BadRequestException("Code not specified", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
}
@@ -435,6 +373,41 @@ public class TokenService {
return Cors.add(request, Response.ok(res)).allowedOrigins(client).allowedMethods("POST").build();
}
+ protected UserModel authorizeClient(String authorizationHeader) {
+ if (authorizationHeader == null) {
+ throw new NotAuthorizedException("No Authorization header to authenticate client", "Basic realm=\"" + realm.getName() + "\"");
+ }
+
+ String[] usernameSecret = BasicAuthHelper.parseHeader(authorizationHeader);
+ if (usernameSecret == null) {
+ throw new NotAuthorizedException("No Authorization header to authenticate client", "Basic realm=\"" + realm.getName() + "\"");
+ }
+
+ String client_id = usernameSecret[0];
+ String clientSecret = usernameSecret[1];
+ UserModel client = realm.getUser(client_id);
+ if (client == null) {
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_client");
+ error.put("error_description", "Could not find client");
+ throw new BadRequestException("Could not find client", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
+ }
+
+ if (!client.isEnabled()) {
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_client");
+ error.put("error_description", "Client is not enabled");
+ throw new BadRequestException("Client is not enabled", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
+ }
+
+ if (!realm.validateSecret(client, clientSecret)) {
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "unauthorized_client");
+ throw new BadRequestException("Unauthorized Client", Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build());
+ }
+ return client;
+ }
+
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, AccessToken token) {
String encodedToken = new JWSBuilder().jsonContent(token).rsa256(privateKey);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
index adc8bf5..720ea52 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
@@ -57,7 +57,7 @@ public class CompositeRoleTest {
RealmModel realm = manager.createRealm("Test");
manager.generateRealmKeys(realm);
realmPublicKey = realm.getPublicKey();
- realm.setTokenLifespan(10000);
+ realm.setAccessTokenLifespan(10000);
realm.setAccessCodeLifespanUserAction(1000);
realm.setAccessCodeLifespan(1000);
realm.setSslNotRequired(true);
diff --git a/testsuite/integration/src/test/resources/testcomposite.json b/testsuite/integration/src/test/resources/testcomposite.json
index 19b662e..cfdd2c7 100755
--- a/testsuite/integration/src/test/resources/testcomposite.json
+++ b/testsuite/integration/src/test/resources/testcomposite.json
@@ -2,7 +2,7 @@
"id": "Test",
"realm": "Test",
"enabled": true,
- "tokenLifespan": 600,
+ "accessTokenLifespan": 600,
"accessCodeLifespan": 600,
"accessCodeLifespanUserAction": 600,
"sslNotRequired": true,
diff --git a/testsuite/integration/src/test/resources/testrealm.json b/testsuite/integration/src/test/resources/testrealm.json
index e040c2c..72db7ca 100755
--- a/testsuite/integration/src/test/resources/testrealm.json
+++ b/testsuite/integration/src/test/resources/testrealm.json
@@ -2,7 +2,7 @@
"id": "test",
"realm": "test",
"enabled": true,
- "tokenLifespan": 600,
+ "accessTokenLifespan": 600,
"accessCodeLifespan": 600,
"accessCodeLifespanUserAction": 600,
"sslNotRequired": true,