Merge pull request #233 from patriot1burke/master
refactor token creation
This commit is contained in:
commit
15968e9783
27 changed files with 243 additions and 184 deletions
|
@ -11,13 +11,13 @@
|
||||||
<form class="form-horizontal" name="realmForm" novalidate>
|
<form class="form-horizontal" name="realmForm" novalidate>
|
||||||
<fieldset class="border-top">
|
<fieldset class="border-top">
|
||||||
<div class="form-group input-select">
|
<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="col-sm-10">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<input class="form-control" type="number" required min="1"
|
<input class="form-control" type="number" required min="1"
|
||||||
max="31536000" data-ng-model="realm.tokenLifespan"
|
max="31536000" data-ng-model="realm.accessTokenLifespan"
|
||||||
id="tokenLifespan" name="tokenLifespan"/>
|
id="accessTokenLifespan" name="accessTokenLifespan"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2 select-kc">
|
<div class="col-sm-2 select-kc">
|
||||||
<select name="tokenLifespanUnit" data-ng-model="realm.tokenLifespanUnit" >
|
<select name="tokenLifespanUnit" data-ng-model="realm.tokenLifespanUnit" >
|
||||||
|
|
|
@ -19,6 +19,19 @@ public class AccessToken extends JsonWebToken {
|
||||||
@JsonProperty("verify_caller")
|
@JsonProperty("verify_caller")
|
||||||
protected Boolean verifyCaller;
|
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() {
|
public Set<String> getRoles() {
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
36
core/src/main/java/org/keycloak/representations/RefreshToken.java
Executable file
36
core/src/main/java/org/keycloak/representations/RefreshToken.java
Executable file
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,9 +29,6 @@ public class PublishedRealmRepresentation {
|
||||||
@JsonProperty("grants")
|
@JsonProperty("grants")
|
||||||
protected String grantUrl;
|
protected String grantUrl;
|
||||||
|
|
||||||
@JsonProperty("identity-grants")
|
|
||||||
protected String identityGrantUrl;
|
|
||||||
|
|
||||||
@JsonProperty("admin-role")
|
@JsonProperty("admin-role")
|
||||||
protected String adminRole;
|
protected String adminRole;
|
||||||
|
|
||||||
|
@ -124,12 +121,4 @@ public class PublishedRealmRepresentation {
|
||||||
public void setGrantUrl(String grantUrl) {
|
public void setGrantUrl(String grantUrl) {
|
||||||
this.grantUrl = grantUrl;
|
this.grantUrl = grantUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIdentityGrantUrl() {
|
|
||||||
return identityGrantUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIdentityGrantUrl(String identityGrantUrl) {
|
|
||||||
this.identityGrantUrl = identityGrantUrl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class RealmRepresentation {
|
||||||
protected String self; // link
|
protected String self; // link
|
||||||
protected String id;
|
protected String id;
|
||||||
protected String realm;
|
protected String realm;
|
||||||
protected Integer tokenLifespan;
|
protected Integer accessTokenLifespan;
|
||||||
protected Integer accessCodeLifespan;
|
protected Integer accessCodeLifespan;
|
||||||
protected Integer accessCodeLifespanUserAction;
|
protected Integer accessCodeLifespanUserAction;
|
||||||
protected Boolean enabled;
|
protected Boolean enabled;
|
||||||
|
@ -114,12 +114,12 @@ public class RealmRepresentation {
|
||||||
this.sslNotRequired = sslNotRequired;
|
this.sslNotRequired = sslNotRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getTokenLifespan() {
|
public Integer getAccessTokenLifespan() {
|
||||||
return tokenLifespan;
|
return accessTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTokenLifespan(Integer tokenLifespan) {
|
public void setAccessTokenLifespan(Integer accessTokenLifespan) {
|
||||||
this.tokenLifespan = tokenLifespan;
|
this.accessTokenLifespan = accessTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserRoleMappingRepresentation> getRoleMappings() {
|
public List<UserRoleMappingRepresentation> getRoleMappings() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"realm": "demo",
|
"realm": "demo",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 3000,
|
"accessTokenLifespan": 3000,
|
||||||
"accessCodeLifespan": 10,
|
"accessCodeLifespan": 10,
|
||||||
"accessCodeLifespanUserAction": 6000,
|
"accessCodeLifespanUserAction": 6000,
|
||||||
"sslNotRequired": true,
|
"sslNotRequired": true,
|
||||||
|
|
|
@ -38,9 +38,13 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
|
||||||
|
|
||||||
void setResetPasswordAllowed(boolean resetPasswordAllowed);
|
void setResetPasswordAllowed(boolean resetPasswordAllowed);
|
||||||
|
|
||||||
int getTokenLifespan();
|
int getAccessTokenLifespan();
|
||||||
|
|
||||||
void setTokenLifespan(int tokenLifespan);
|
void setAccessTokenLifespan(int tokenLifespan);
|
||||||
|
|
||||||
|
int getRefreshTokenLifespan();
|
||||||
|
|
||||||
|
void setRefreshTokenLifespan(int tokenLifespan);
|
||||||
|
|
||||||
int getAccessCodeLifespan();
|
int getAccessCodeLifespan();
|
||||||
|
|
||||||
|
|
|
@ -128,13 +128,24 @@ public class RealmAdapter implements RealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTokenLifespan() {
|
public int getAccessTokenLifespan() {
|
||||||
return realm.getTokenLifespan();
|
return realm.getAccessTokenLifespan();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTokenLifespan(int tokenLifespan) {
|
public void setAccessTokenLifespan(int tokenLifespan) {
|
||||||
realm.setTokenLifespan(tokenLifespan);
|
realm.setAccessTokenLifespan(tokenLifespan);
|
||||||
|
em.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRefreshTokenLifespan() {
|
||||||
|
return realm.getRefreshTokenLifespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRefreshTokenLifespan(int tokenLifespan) {
|
||||||
|
realm.setRefreshTokenLifespan(tokenLifespan);
|
||||||
em.flush();
|
em.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,10 @@ public class RealmEntity {
|
||||||
protected boolean updateProfileOnInitialSocialLogin;
|
protected boolean updateProfileOnInitialSocialLogin;
|
||||||
protected String passwordPolicy;
|
protected String passwordPolicy;
|
||||||
|
|
||||||
protected int tokenLifespan;
|
protected int accessTokenLifespan;
|
||||||
protected int accessCodeLifespan;
|
protected int accessCodeLifespan;
|
||||||
protected int accessCodeLifespanUserAction;
|
protected int accessCodeLifespanUserAction;
|
||||||
|
protected int refreshTokenLifespan;
|
||||||
|
|
||||||
@Column(length = 2048)
|
@Column(length = 2048)
|
||||||
protected String publicKeyPem;
|
protected String publicKeyPem;
|
||||||
|
@ -161,12 +162,20 @@ public class RealmEntity {
|
||||||
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
|
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTokenLifespan() {
|
public int getRefreshTokenLifespan() {
|
||||||
return tokenLifespan;
|
return refreshTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTokenLifespan(int tokenLifespan) {
|
public void setRefreshTokenLifespan(int refreshTokenLifespan) {
|
||||||
this.tokenLifespan = tokenLifespan;
|
this.refreshTokenLifespan = refreshTokenLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAccessTokenLifespan() {
|
||||||
|
return accessTokenLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessTokenLifespan(int accessTokenLifespan) {
|
||||||
|
this.accessTokenLifespan = accessTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAccessCodeLifespan() {
|
public int getAccessCodeLifespan() {
|
||||||
|
|
|
@ -167,13 +167,24 @@ public class RealmAdapter extends AbstractAdapter implements RealmModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTokenLifespan() {
|
public int getAccessTokenLifespan() {
|
||||||
return realm.getTokenLifespan();
|
return realm.getAccessTokenLifespan();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTokenLifespan(int tokenLifespan) {
|
public void setAccessTokenLifespan(int tokenLifespan) {
|
||||||
realm.setTokenLifespan(tokenLifespan);
|
realm.setAccessTokenLifespan(tokenLifespan);
|
||||||
|
updateRealm();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRefreshTokenLifespan() {
|
||||||
|
return realm.getRefreshTokenLifespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRefreshTokenLifespan(int tokenLifespan) {
|
||||||
|
realm.setRefreshTokenLifespan(tokenLifespan);
|
||||||
updateRealm();
|
updateRealm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,10 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong
|
||||||
private boolean updateProfileOnInitialSocialLogin;
|
private boolean updateProfileOnInitialSocialLogin;
|
||||||
private String passwordPolicy;
|
private String passwordPolicy;
|
||||||
|
|
||||||
private int tokenLifespan;
|
private int accessTokenLifespan;
|
||||||
private int accessCodeLifespan;
|
private int accessCodeLifespan;
|
||||||
private int accessCodeLifespanUserAction;
|
private int accessCodeLifespanUserAction;
|
||||||
|
private int refreshTokenLifespan;
|
||||||
|
|
||||||
private String publicKeyPem;
|
private String publicKeyPem;
|
||||||
private String privateKeyPem;
|
private String privateKeyPem;
|
||||||
|
@ -131,12 +132,21 @@ public class RealmEntity extends AbstractMongoIdentifiableEntity implements Mong
|
||||||
}
|
}
|
||||||
|
|
||||||
@MongoField
|
@MongoField
|
||||||
public int getTokenLifespan() {
|
public int getAccessTokenLifespan() {
|
||||||
return tokenLifespan;
|
return accessTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTokenLifespan(int tokenLifespan) {
|
public void setAccessTokenLifespan(int accessTokenLifespan) {
|
||||||
this.tokenLifespan = tokenLifespan;
|
this.accessTokenLifespan = accessTokenLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MongoField
|
||||||
|
public int getRefreshTokenLifespan() {
|
||||||
|
return refreshTokenLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshTokenLifespan(int refreshTokenLifespan) {
|
||||||
|
this.refreshTokenLifespan = refreshTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MongoField
|
@MongoField
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
realmModel.setName("JUGGLER");
|
realmModel.setName("JUGGLER");
|
||||||
realmModel.setPrivateKeyPem("0234234");
|
realmModel.setPrivateKeyPem("0234234");
|
||||||
realmModel.setPublicKeyPem("0234234");
|
realmModel.setPublicKeyPem("0234234");
|
||||||
realmModel.setTokenLifespan(1000);
|
realmModel.setAccessTokenLifespan(1000);
|
||||||
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
||||||
realmModel.addDefaultRole("foo");
|
realmModel.addDefaultRole("foo");
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
Assert.assertNotNull(realmModel);
|
Assert.assertNotNull(realmModel);
|
||||||
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
||||||
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
|
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
|
||||||
Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
|
Assert.assertEquals(realmModel.getAccessTokenLifespan(), 1000);
|
||||||
Assert.assertEquals(realmModel.isEnabled(), true);
|
Assert.assertEquals(realmModel.isEnabled(), true);
|
||||||
Assert.assertEquals(realmModel.getName(), "JUGGLER");
|
Assert.assertEquals(realmModel.getName(), "JUGGLER");
|
||||||
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
|
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
|
||||||
|
@ -75,7 +75,7 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
realmModel.setName("JUGGLER");
|
realmModel.setName("JUGGLER");
|
||||||
realmModel.setPrivateKeyPem("0234234");
|
realmModel.setPrivateKeyPem("0234234");
|
||||||
realmModel.setPublicKeyPem("0234234");
|
realmModel.setPublicKeyPem("0234234");
|
||||||
realmModel.setTokenLifespan(1000);
|
realmModel.setAccessTokenLifespan(1000);
|
||||||
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
realmModel.setUpdateProfileOnInitialSocialLogin(true);
|
||||||
realmModel.addDefaultRole("foo");
|
realmModel.addDefaultRole("foo");
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ public class AdapterTest extends AbstractModelTest {
|
||||||
Assert.assertNotNull(realmModel);
|
Assert.assertNotNull(realmModel);
|
||||||
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
|
||||||
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
|
Assert.assertEquals(600, realmModel.getAccessCodeLifespanUserAction());
|
||||||
Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
|
Assert.assertEquals(realmModel.getAccessTokenLifespan(), 1000);
|
||||||
Assert.assertEquals(realmModel.isEnabled(), true);
|
Assert.assertEquals(realmModel.isEnabled(), true);
|
||||||
Assert.assertEquals(realmModel.getName(), "JUGGLER");
|
Assert.assertEquals(realmModel.getName(), "JUGGLER");
|
||||||
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
|
Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
|
||||||
realm.setName("Test");
|
realm.setName("Test");
|
||||||
realm.setPrivateKeyPem("0234234");
|
realm.setPrivateKeyPem("0234234");
|
||||||
realm.setPublicKeyPem("0234234");
|
realm.setPublicKeyPem("0234234");
|
||||||
realm.setTokenLifespan(1000);
|
realm.setAccessTokenLifespan(1000);
|
||||||
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
||||||
|
|
||||||
am = new AuthenticationManager();
|
am = new AuthenticationManager();
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class ModelTest extends AbstractModelTest {
|
||||||
realm.setSocial(true);
|
realm.setSocial(true);
|
||||||
realm.setSslNotRequired(true);
|
realm.setSslNotRequired(true);
|
||||||
realm.setVerifyEmail(true);
|
realm.setVerifyEmail(true);
|
||||||
realm.setTokenLifespan(1000);
|
realm.setAccessTokenLifespan(1000);
|
||||||
realm.setPasswordPolicy(new PasswordPolicy("length"));
|
realm.setPasswordPolicy(new PasswordPolicy("length"));
|
||||||
realm.setAccessCodeLifespan(1001);
|
realm.setAccessCodeLifespan(1001);
|
||||||
realm.setAccessCodeLifespanUserAction(1002);
|
realm.setAccessCodeLifespanUserAction(1002);
|
||||||
|
@ -55,7 +55,7 @@ public class ModelTest extends AbstractModelTest {
|
||||||
Assert.assertEquals(expected.isSocial(), actual.isSocial());
|
Assert.assertEquals(expected.isSocial(), actual.isSocial());
|
||||||
Assert.assertEquals(expected.isSslNotRequired(), actual.isSslNotRequired());
|
Assert.assertEquals(expected.isSslNotRequired(), actual.isSslNotRequired());
|
||||||
Assert.assertEquals(expected.isVerifyEmail(), actual.isVerifyEmail());
|
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.getAccessCodeLifespan(), actual.getAccessCodeLifespan());
|
||||||
Assert.assertEquals(expected.getAccessCodeLifespanUserAction(), actual.getAccessCodeLifespanUserAction());
|
Assert.assertEquals(expected.getAccessCodeLifespanUserAction(), actual.getAccessCodeLifespanUserAction());
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "Test",
|
"id": "Test",
|
||||||
"realm": "Test",
|
"realm": "Test",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 600,
|
"accessTokenLifespan": 600,
|
||||||
"accessCodeLifespan": 600,
|
"accessCodeLifespan": 600,
|
||||||
"accessCodeLifespanUserAction": 600,
|
"accessCodeLifespanUserAction": 600,
|
||||||
"sslNotRequired": true,
|
"sslNotRequired": true,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"realm": "demo",
|
"realm": "demo",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 300,
|
"accessTokenLifespan": 300,
|
||||||
"accessCodeLifespan": 10,
|
"accessCodeLifespan": 10,
|
||||||
"accessCodeLifespanUserAction": 600,
|
"accessCodeLifespanUserAction": 600,
|
||||||
"sslNotRequired": true,
|
"sslNotRequired": true,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"realm": "test-realm",
|
"realm": "test-realm",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 6000,
|
"accessTokenLifespan": 6000,
|
||||||
"accessCodeLifespan": 30,
|
"accessCodeLifespan": 30,
|
||||||
"accessCodeLifespanUserAction": 600,
|
"accessCodeLifespanUserAction": 600,
|
||||||
"requiredCredentials": [ "password" ],
|
"requiredCredentials": [ "password" ],
|
||||||
|
|
|
@ -11,8 +11,6 @@ import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -48,7 +46,7 @@ public class ApplianceBootstrap {
|
||||||
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
||||||
realm.addRequiredOAuthClientCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredOAuthClientCredential(CredentialRepresentation.PASSWORD);
|
||||||
realm.addRequiredResourceCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredResourceCredential(CredentialRepresentation.PASSWORD);
|
||||||
realm.setTokenLifespan(300);
|
realm.setAccessTokenLifespan(300);
|
||||||
realm.setAccessCodeLifespan(60);
|
realm.setAccessCodeLifespan(60);
|
||||||
realm.setAccessCodeLifespanUserAction(300);
|
realm.setAccessCodeLifespanUserAction(300);
|
||||||
realm.setSslNotRequired(true);
|
realm.setSslNotRequired(true);
|
||||||
|
|
|
@ -46,8 +46,8 @@ public class AuthenticationManager {
|
||||||
token.issuedNow();
|
token.issuedNow();
|
||||||
token.subject(user.getId());
|
token.subject(user.getId());
|
||||||
token.audience(realm.getName());
|
token.audience(realm.getName());
|
||||||
if (realm.getTokenLifespan() > 0) {
|
if (realm.getAccessTokenLifespan() > 0) {
|
||||||
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
|
token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class ModelToRepresentation {
|
||||||
rep.setRegistrationAllowed(realm.isRegistrationAllowed());
|
rep.setRegistrationAllowed(realm.isRegistrationAllowed());
|
||||||
rep.setVerifyEmail(realm.isVerifyEmail());
|
rep.setVerifyEmail(realm.isVerifyEmail());
|
||||||
rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
|
rep.setResetPasswordAllowed(realm.isResetPasswordAllowed());
|
||||||
rep.setTokenLifespan(realm.getTokenLifespan());
|
rep.setAccessTokenLifespan(realm.getAccessTokenLifespan());
|
||||||
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
|
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
|
||||||
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
|
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
|
||||||
rep.setSmtpServer(realm.getSmtpConfig());
|
rep.setSmtpServer(realm.getSmtpConfig());
|
||||||
|
|
|
@ -7,7 +7,6 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OAuthClientModel;
|
import org.keycloak.models.OAuthClientModel;
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredCredentialModel;
|
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.SocialLinkModel;
|
import org.keycloak.models.SocialLinkModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
@ -28,14 +27,10 @@ import org.keycloak.representations.idm.UserRoleMappingRepresentation;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per request object
|
* Per request object
|
||||||
|
@ -110,7 +105,7 @@ public class RealmManager {
|
||||||
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||||
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
||||||
if (rep.getTokenLifespan() != null) realm.setTokenLifespan(rep.getTokenLifespan());
|
if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||||
if (rep.getRequiredCredentials() != null) {
|
if (rep.getRequiredCredentials() != null) {
|
||||||
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
||||||
}
|
}
|
||||||
|
@ -163,8 +158,8 @@ public class RealmManager {
|
||||||
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
|
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
|
||||||
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
|
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
|
||||||
|
|
||||||
if (rep.getTokenLifespan() != null) newRealm.setTokenLifespan(rep.getTokenLifespan());
|
if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||||
else newRealm.setTokenLifespan(300);
|
else newRealm.setAccessTokenLifespan(300);
|
||||||
|
|
||||||
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||||
else newRealm.setAccessCodeLifespan(60);
|
else newRealm.setAccessCodeLifespan(60);
|
||||||
|
|
|
@ -12,10 +12,12 @@ import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.util.Base64Url;
|
import org.keycloak.util.Base64Url;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MultivaluedHashMap;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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) {
|
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();
|
AccessCodeEntry code = new AccessCodeEntry();
|
||||||
AccessScope scopeMap = null;
|
|
||||||
if (scopeParam != null) scopeMap = decodeScope(scopeParam);
|
|
||||||
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
|
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
|
||||||
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
|
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> roleMappings = realm.getRoleMappings(user);
|
||||||
Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
|
Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
|
||||||
|
@ -113,22 +147,22 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createToken(code, realm, client, user);
|
AccessToken token = initToken(realm, client, user);
|
||||||
code.setRealm(realm);
|
|
||||||
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
if (realmRolesRequested.size() > 0) {
|
||||||
code.setClient(client);
|
for (RoleModel role : realmRolesRequested) {
|
||||||
code.setUser(user);
|
addComposites(token, role);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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) {
|
protected AccessToken initToken(RealmModel realm, UserModel client, UserModel user) {
|
||||||
|
@ -138,8 +172,8 @@ public class TokenManager {
|
||||||
token.audience(realm.getName());
|
token.audience(realm.getName());
|
||||||
token.issuedNow();
|
token.issuedNow();
|
||||||
token.issuedFor(client.getLoginName());
|
token.issuedFor(client.getLoginName());
|
||||||
if (realm.getTokenLifespan() > 0) {
|
if (realm.getAccessTokenLifespan() > 0) {
|
||||||
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
|
token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
|
||||||
}
|
}
|
||||||
Set<String> allowedOrigins = client.getWebOrigins();
|
Set<String> allowedOrigins = client.getWebOrigins();
|
||||||
if (allowedOrigins != null) {
|
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) {
|
public String encodeScope(AccessScope scope) {
|
||||||
String token = null;
|
String token = null;
|
||||||
try {
|
try {
|
||||||
|
@ -224,8 +238,8 @@ public class TokenManager {
|
||||||
token.issuedNow();
|
token.issuedNow();
|
||||||
token.subject(user.getId());
|
token.subject(user.getId());
|
||||||
token.audience(realm.getName());
|
token.audience(realm.getName());
|
||||||
if (realm.getTokenLifespan() > 0) {
|
if (realm.getAccessTokenLifespan() > 0) {
|
||||||
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
|
token.expiration((System.currentTimeMillis() / 1000) + realm.getAccessTokenLifespan());
|
||||||
}
|
}
|
||||||
for (RoleModel role : realm.getRoleMappings(user)) {
|
for (RoleModel role : realm.getRoleMappings(user)) {
|
||||||
addComposites(token, role);
|
addComposites(token, role);
|
||||||
|
|
|
@ -53,13 +53,11 @@ public class PublicRealmResource {
|
||||||
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString();
|
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString();
|
||||||
String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString();
|
String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString();
|
||||||
String grantUrl = TokenService.grantAccessTokenUrl(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("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
|
||||||
html.append("<p>auth: ").append(authUri).append("</p>");
|
html.append("<p>auth: ").append(authUri).append("</p>");
|
||||||
html.append("<p>code: ").append(codeUri).append("</p>");
|
html.append("<p>code: ").append(codeUri).append("</p>");
|
||||||
html.append("<p>grant: ").append(grantUrl).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("<p>public key: ").append(realm.getPublicKeyPem()).append("</p>");
|
||||||
html.append("</body></html>");
|
html.append("</body></html>");
|
||||||
|
|
||||||
|
@ -77,8 +75,6 @@ public class PublicRealmResource {
|
||||||
rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString());
|
rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getName()).toString());
|
||||||
rep.setCodeUrl(TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString());
|
rep.setCodeUrl(TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getName()).toString());
|
||||||
rep.setGrantUrl(TokenService.grantAccessTokenUrl(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;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.keycloak.services.resources.flows.OAuthFlows;
|
||||||
import org.keycloak.services.validation.Validation;
|
import org.keycloak.services.validation.Validation;
|
||||||
import org.keycloak.util.BasicAuthHelper;
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
|
|
||||||
|
import javax.ws.rs.BadRequestException;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.HeaderParam;
|
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) {
|
public static UriBuilder loginPageUrl(UriInfo uriInfo) {
|
||||||
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "loginPage");
|
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "loginPage");
|
||||||
}
|
}
|
||||||
|
@ -129,45 +125,19 @@ public class TokenService {
|
||||||
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
|
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("grants/identity-token")
|
|
||||||
@POST
|
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public Response grantIdentityToken(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("grants/access")
|
@Path("grants/access")
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response grantAccessToken(final MultivaluedMap<String, String> form) {
|
public Response grantAccessToken(final @HeaderParam(HttpHeaders.AUTHORIZATION) String authorizationHeader,
|
||||||
|
final MultivaluedMap<String, String> form) {
|
||||||
if (!checkSsl()) {
|
if (!checkSsl()) {
|
||||||
throw new NotAcceptableException("HTTPS required");
|
throw new NotAcceptableException("HTTPS required");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UserModel client = authorizeClient(authorizationHeader);
|
||||||
|
|
||||||
|
|
||||||
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
|
String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
throw new NotAuthorizedException("No user");
|
throw new NotAuthorizedException("No user");
|
||||||
|
@ -185,7 +155,8 @@ public class TokenService {
|
||||||
if (authManager.authenticateForm(realm, user, form) != AuthenticationStatus.SUCCESS) {
|
if (authManager.authenticateForm(realm, user, form) != AuthenticationStatus.SUCCESS) {
|
||||||
throw new NotAuthorizedException("Auth failed");
|
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);
|
String encoded = tokenManager.encodeToken(realm, token);
|
||||||
AccessTokenResponse res = accessTokenResponse(token, encoded);
|
AccessTokenResponse res = accessTokenResponse(token, encoded);
|
||||||
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
|
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
|
||||||
|
@ -341,47 +312,14 @@ public class TokenService {
|
||||||
throw new NotAuthorizedException("Realm not enabled");
|
throw new NotAuthorizedException("Realm not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authorizationHeader == null) {
|
UserModel client = authorizeClient(authorizationHeader);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
String code = formData.getFirst("code");
|
String code = formData.getFirst("code");
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
logger.debug("code not specified");
|
|
||||||
Map<String, String> error = new HashMap<String, String>();
|
Map<String, String> error = new HashMap<String, String>();
|
||||||
error.put("error", "invalid_request");
|
error.put("error", "invalid_request");
|
||||||
error.put("error_description", "code not specified");
|
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();
|
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) {
|
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, AccessToken token) {
|
||||||
String encodedToken = new JWSBuilder().jsonContent(token).rsa256(privateKey);
|
String encodedToken = new JWSBuilder().jsonContent(token).rsa256(privateKey);
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class CompositeRoleTest {
|
||||||
RealmModel realm = manager.createRealm("Test");
|
RealmModel realm = manager.createRealm("Test");
|
||||||
manager.generateRealmKeys(realm);
|
manager.generateRealmKeys(realm);
|
||||||
realmPublicKey = realm.getPublicKey();
|
realmPublicKey = realm.getPublicKey();
|
||||||
realm.setTokenLifespan(10000);
|
realm.setAccessTokenLifespan(10000);
|
||||||
realm.setAccessCodeLifespanUserAction(1000);
|
realm.setAccessCodeLifespanUserAction(1000);
|
||||||
realm.setAccessCodeLifespan(1000);
|
realm.setAccessCodeLifespan(1000);
|
||||||
realm.setSslNotRequired(true);
|
realm.setSslNotRequired(true);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "Test",
|
"id": "Test",
|
||||||
"realm": "Test",
|
"realm": "Test",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 600,
|
"accessTokenLifespan": 600,
|
||||||
"accessCodeLifespan": 600,
|
"accessCodeLifespan": 600,
|
||||||
"accessCodeLifespanUserAction": 600,
|
"accessCodeLifespanUserAction": 600,
|
||||||
"sslNotRequired": true,
|
"sslNotRequired": true,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "test",
|
"id": "test",
|
||||||
"realm": "test",
|
"realm": "test",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"tokenLifespan": 600,
|
"accessTokenLifespan": 600,
|
||||||
"accessCodeLifespan": 600,
|
"accessCodeLifespan": 600,
|
||||||
"accessCodeLifespanUserAction": 600,
|
"accessCodeLifespanUserAction": 600,
|
||||||
"sslNotRequired": true,
|
"sslNotRequired": true,
|
||||||
|
|
Loading…
Reference in a new issue