token service refactoring

This commit is contained in:
Bill Burke committed 2014-09-30 15:58:20 -04:00
1 parent fc867e59ea
commit 63b65c933b
19 files changed
+66 -247

No files matched your search

@@ -1,4 +1,4 @@
package org.keycloak.services.resources;
package org.keycloak.protocol.oidc;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
@@ -7,7 +7,6 @@ import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotAcceptableException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
@@ -27,8 +26,6 @@ import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.oidc.OpenIDConnect;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.RefreshToken;
@@ -37,6 +34,8 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthenticationStatus;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.util.Base64Url;
@@ -72,9 +71,9 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class TokenService {
public class OpenIDConnectService {
protected static final Logger logger = Logger.getLogger(TokenService.class);
protected static final Logger logger = Logger.getLogger(OpenIDConnectService.class);
protected RealmModel realm;
protected TokenManager tokenManager;
@@ -103,7 +102,7 @@ public class TokenService {
protected ResourceContext resourceContext;
*/
public TokenService(RealmModel realm, TokenManager tokenManager, EventBuilder event, AuthenticationManager authManager) {
public OpenIDConnectService(RealmModel realm, TokenManager tokenManager, EventBuilder event, AuthenticationManager authManager) {
this.realm = realm;
this.tokenManager = tokenManager;
this.event = event;
@@ -127,12 +126,12 @@ public class TokenService {
public static UriBuilder accessCodeToTokenUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "accessCodeToToken");
return uriBuilder.path(OpenIDConnectService.class, "accessCodeToToken");
}
public static UriBuilder validateAccessTokenUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "validateAccessToken");
return uriBuilder.path(OpenIDConnectService.class, "validateAccessToken");
}
public static UriBuilder grantAccessTokenUrl(UriInfo uriInfo) {
@@ -143,7 +142,7 @@ public class TokenService {
public static UriBuilder grantAccessTokenUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "grantAccessToken");
return uriBuilder.path(OpenIDConnectService.class, "grantAccessToken");
}
public static UriBuilder loginPageUrl(UriInfo uriInfo) {
@@ -153,7 +152,7 @@ public class TokenService {
public static UriBuilder loginPageUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "loginPage");
return uriBuilder.path(OpenIDConnectService.class, "loginPage");
}
public static UriBuilder logoutUrl(UriInfo uriInfo) {
@@ -163,12 +162,12 @@ public class TokenService {
public static UriBuilder logoutUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "logout");
return uriBuilder.path(OpenIDConnectService.class, "logout");
}
public static UriBuilder refreshUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "refreshAccessToken");
return uriBuilder.path(OpenIDConnectService.class, "refreshAccessToken");
}
@@ -1,171 +0,0 @@
package org.keycloak.services.managers;
import org.keycloak.OAuthErrorException;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.util.Base64Url;
import org.keycloak.util.Time;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.Signature;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AccessCode {
private final RealmModel realm;
private final ClientSessionModel clientSession;
public AccessCode(RealmModel realm, ClientSessionModel clientSession) {
this.realm = realm;
this.clientSession = clientSession;
}
public static AccessCode parse(String code, KeycloakSession session, RealmModel realm) {
try {
String[] parts = code.split("\\.");
String id = new String(Base64Url.decode(parts[1]));
ClientSessionModel clientSession = session.sessions().getClientSession(realm, id);
if (clientSession == null) {
return null;
}
String hash = createSignatureHash(realm, clientSession);
if (!hash.equals(parts[0])) {
return null;
}
return new AccessCode(realm, clientSession);
} catch (RuntimeException e) {
return null;
}
}
public String getCodeId() {
return clientSession.getId();
}
public UserModel getUser() {
return clientSession.getUserSession().getUser();
}
public String getSessionState() {
return clientSession.getUserSession().getId();
}
public boolean isValid(RequiredAction requiredAction) {
return isValid(convertToAction(requiredAction));
}
public boolean isValid(ClientSessionModel.Action requestedAction) {
ClientSessionModel.Action action = clientSession.getAction();
if (action == null) {
return false;
}
int timestamp = clientSession.getTimestamp();
if (!action.equals(requestedAction)) {
return false;
}
int lifespan = action.equals(ClientSessionModel.Action.CODE_TO_TOKEN) ? realm.getAccessCodeLifespan() : realm.getAccessCodeLifespanUserAction();
return timestamp + lifespan > Time.currentTime();
}
public Set<RoleModel> getRequestedRoles() {
Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
for (String roleId : clientSession.getRoles()) {
RoleModel role = realm.getRoleById(roleId);
if (role == null) {
new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid role " + roleId);
}
requestedRoles.add(realm.getRoleById(roleId));
}
return requestedRoles;
}
public ClientModel getClient() {
return clientSession.getClient();
}
public String getState() {
throw new RuntimeException("REFACTORING, TODO REMOVE ACCESS CODE");
}
public String getRedirectUri() {
return clientSession.getRedirectUri();
}
public ClientSessionModel.Action getAction() {
return clientSession.getAction();
}
public void setAction(ClientSessionModel.Action action) {
clientSession.setAction(action);
clientSession.setTimestamp(Time.currentTime());
}
public void setRequiredAction(RequiredAction requiredAction) {
setAction(convertToAction(requiredAction));
}
private ClientSessionModel.Action convertToAction(RequiredAction requiredAction) {
switch (requiredAction) {
case CONFIGURE_TOTP:
return ClientSessionModel.Action.CONFIGURE_TOTP;
case UPDATE_PASSWORD:
return ClientSessionModel.Action.UPDATE_PASSWORD;
case UPDATE_PROFILE:
return ClientSessionModel.Action.UPDATE_PROFILE;
case VERIFY_EMAIL:
return ClientSessionModel.Action.VERIFY_EMAIL;
default:
throw new IllegalArgumentException("Unknown required action " + requiredAction);
}
}
public String getCode() {
String hash = createSignatureHash(realm, clientSession);
StringBuilder sb = new StringBuilder();
sb.append(hash);
sb.append(".");
sb.append(Base64Url.encode(clientSession.getId().getBytes()));
return sb.toString();
}
private static String createSignatureHash(RealmModel realm, ClientSessionModel clientSession) {
try {
Signature signature = Signature.getInstance(RSAProvider.getJavaAlgorithm(Algorithm.RS256));
signature.initSign(realm.getPrivateKey());
signature.update(clientSession.getId().getBytes());
signature.update(ByteBuffer.allocate(4).putInt(clientSession.getTimestamp()));
if (clientSession.getAction() != null) {
signature.update(clientSession.getAction().toString().getBytes());
}
byte[] sign = signature.sign();
MessageDigest digest = MessageDigest.getInstance("sha-1");
digest.update(sign);
return Base64Url.encode(digest.digest());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -48,6 +48,7 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.protocol.oidc.OpenIDConnect;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.ForbiddenException;
@@ -794,7 +795,7 @@ public class AccountService {
ApplicationModel application = realm.getApplicationByName(referrer);
if (application != null) {
if (referrerUri != null) {
referrerUri = TokenService.verifyRedirectUri(uriInfo, referrerUri, realm, application);
referrerUri = OpenIDConnectService.verifyRedirectUri(uriInfo, referrerUri, realm, application);
} else {
referrerUri = ResolveRelative.resolveRelativeUri(uriInfo.getRequestUri(), application.getBaseUrl());
}
@@ -805,7 +806,7 @@ public class AccountService {
} else if (referrerUri != null) {
ClientModel client = realm.getOAuthClient(referrer);
if (client != null) {
referrerUri = TokenService.verifyRedirectUri(uriInfo, referrerUri, realm, application);
referrerUri = OpenIDConnectService.verifyRedirectUri(uriInfo, referrerUri, realm, application);
if (referrerUri != null) {
return new String[]{referrer, referrerUri};
@@ -73,7 +73,7 @@ public class KeycloakApplication extends Application {
singletons.add(new ServerVersionResource());
singletons.add(new RealmsResource(tokenManager));
singletons.add(new SocialResource(tokenManager));
singletons.add(new SocialResource());
singletons.add(new AdminRoot(tokenManager));
classes.add(SkeletonKeyContextResolver.class);
classes.add(QRCodeResource.class);
@@ -24,7 +24,6 @@ package org.keycloak.services.resources;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.ClientConnection;
import org.keycloak.OAuth2Constants;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
@@ -45,6 +44,7 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.representations.PasswordToken;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
@@ -120,7 +120,7 @@ public class LoginActionsService {
public static UriBuilder processLoginUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = loginActionsBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "processLogin");
return uriBuilder.path(OpenIDConnectService.class, "processLogin");
}
public static UriBuilder processOAuthUrl(UriInfo uriInfo) {
@@ -130,7 +130,7 @@ public class LoginActionsService {
public static UriBuilder processOAuthUrl(UriBuilder baseUriBuilder) {
UriBuilder uriBuilder = loginActionsBaseUrl(baseUriBuilder);
return uriBuilder.path(TokenService.class, "processOAuth");
return uriBuilder.path(OpenIDConnectService.class, "processOAuth");
}
public LoginActionsService(RealmModel realm, AuthenticationManager authManager, EventBuilder event) {
@@ -5,6 +5,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.resources.admin.AdminRoot;
@@ -67,7 +68,7 @@ public class PublicRealmResource {
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {
PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName());
rep.setTokenServiceUrl(TokenService.tokenServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setTokenServiceUrl(OpenIDConnectService.tokenServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAccountServiceUrl(AccountService.accountServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAdminApiUrl(uriInfo.getBaseUriBuilder().path(AdminRoot.class).build().toString());
rep.setPublicKeyPem(realm.getPublicKeyPem());
@@ -1,7 +1,6 @@
package org.keycloak.services.resources;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
@@ -13,6 +12,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.services.managers.EventsManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
@@ -94,8 +94,6 @@ public class RealmsResource {
public Response getLoginStatusIframe(final @PathParam("realm") String name,
@QueryParam("client_id") String client_id,
@QueryParam("origin") String origin) {
AuthenticationManager auth = new AuthenticationManager();
RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager);
ClientModel client = realm.findClient(client_id);
@@ -114,7 +112,7 @@ public class RealmsResource {
}
}
for (String r : TokenService.resolveValidRedirects(uriInfo, client.getRedirectUris())) {
for (String r : OpenIDConnectService.resolveValidRedirects(uriInfo, client.getRedirectUris())) {
int i = r.indexOf('/', 8);
if (i != -1) {
r = r.substring(0, i);
@@ -145,12 +143,12 @@ public class RealmsResource {
}
@Path("{realm}/tokens")
public TokenService getTokenService(final @PathParam("realm") String name) {
public OpenIDConnectService getTokenService(final @PathParam("realm") String name) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager);
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
AuthenticationManager authManager = new AuthenticationManager(protector);
TokenService tokenService = new TokenService(realm, tokenManager, event, authManager);
OpenIDConnectService tokenService = new OpenIDConnectService(realm, tokenManager, event, authManager);
ResteasyProviderFactory.getInstance().injectProperties(tokenService);
//resourceContext.initResource(tokenService);
return tokenService;
@@ -95,12 +95,6 @@ public class SocialResource {
@Context
protected ClientConnection clientConnection;
private TokenManager tokenManager;
public SocialResource(TokenManager tokenManager) {
this.tokenManager = tokenManager;
}
@GET
@Path("callback")
public Response callback(@QueryParam("state") String encodedState) throws URISyntaxException, IOException {
@@ -23,7 +23,7 @@ import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.TokenService;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
@@ -256,7 +256,7 @@ public class AdminConsole {
URI redirect = AdminRoot.adminConsoleUrl(uriInfo).path("index.html").build(realm.getName());
return Response.status(302).location(
TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName())
OpenIDConnectService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName())
).build();
}
@@ -23,10 +23,10 @@ package org.keycloak.services.resources.flows;
import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.protocol.oidc.OpenIDConnectService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.SocialResource;
import org.keycloak.services.resources.ThemeResource;
import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
@@ -137,11 +137,11 @@ public class Urls {
}
public static URI realmLoginPage(URI baseUri, String realmId) {
return tokenBase(baseUri).path(TokenService.class, "loginPage").build(realmId);
return tokenBase(baseUri).path(OpenIDConnectService.class, "loginPage").build(realmId);
}
public static UriBuilder realmLogout(URI baseUri) {
return tokenBase(baseUri).path(TokenService.class, "logout");
return tokenBase(baseUri).path(OpenIDConnectService.class, "logout");
}
public static URI realmRegisterAction(URI baseUri, String realmId) {
@@ -149,11 +149,11 @@ public class Urls {
}
public static URI realmRegisterPage(URI baseUri, String realmId) {
return tokenBase(baseUri).path(TokenService.class, "registerPage").build(realmId);
return tokenBase(baseUri).path(OpenIDConnectService.class, "registerPage").build(realmId);
}
public static URI realmInstalledAppUrnCallback(URI baseUri, String realmId) {
return tokenBase(baseUri).path(TokenService.class, "installedAppUrnCallback").build(realmId);
return tokenBase(baseUri).path(OpenIDConnectService.class, "installedAppUrnCallback").build(realmId);
}
public static URI realmOauthAction(URI baseUri, String realmId) {
@@ -161,7 +161,7 @@ public class Urls {
}
public static URI realmCode(URI baseUri, String realmId) {
return tokenBase(baseUri).path(TokenService.class, "accessCodeToToken").build(realmId);
return tokenBase(baseUri).path(OpenIDConnectService.class, "accessCodeToToken").build(realmId);
}
public static UriBuilder socialBase(URI baseUri) {