KEYCLOAK-2286 Remove deprecated OpenID Connect endpoints
This commit is contained in:
parent
81fc03b3fe
commit
bc845bed0e
5 changed files with 3 additions and 257 deletions
|
@ -14,9 +14,7 @@ import org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint;
|
||||||
import org.keycloak.protocol.oidc.endpoints.LoginStatusIframeEndpoint;
|
import org.keycloak.protocol.oidc.endpoints.LoginStatusIframeEndpoint;
|
||||||
import org.keycloak.protocol.oidc.endpoints.LogoutEndpoint;
|
import org.keycloak.protocol.oidc.endpoints.LogoutEndpoint;
|
||||||
import org.keycloak.protocol.oidc.endpoints.TokenEndpoint;
|
import org.keycloak.protocol.oidc.endpoints.TokenEndpoint;
|
||||||
import org.keycloak.protocol.oidc.endpoints.TokenIntrospectionEndpoint;
|
|
||||||
import org.keycloak.protocol.oidc.endpoints.UserInfoEndpoint;
|
import org.keycloak.protocol.oidc.endpoints.UserInfoEndpoint;
|
||||||
import org.keycloak.protocol.oidc.endpoints.ValidateTokenEndpoint;
|
|
||||||
import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
|
import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
|
||||||
|
@ -88,17 +86,6 @@ public class OIDCLoginProtocolService {
|
||||||
return tokenUrl(baseUriBuilder).path(TokenEndpoint.class, "introspect");
|
return tokenUrl(baseUriBuilder).path(TokenEndpoint.class, "introspect");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link OIDCLoginProtocolService#tokenIntrospectionUrl(UriBuilder)} instead
|
|
||||||
* @param baseUriBuilder
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static UriBuilder validateAccessTokenUrl(UriBuilder baseUriBuilder) {
|
|
||||||
UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
|
|
||||||
return uriBuilder.path(OIDCLoginProtocolService.class, "validateAccessToken");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UriBuilder logoutUrl(UriInfo uriInfo) {
|
public static UriBuilder logoutUrl(UriInfo uriInfo) {
|
||||||
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
|
UriBuilder baseUriBuilder = uriInfo.getBaseUriBuilder();
|
||||||
return logoutUrl(baseUriBuilder);
|
return logoutUrl(baseUriBuilder);
|
||||||
|
@ -149,14 +136,6 @@ public class OIDCLoginProtocolService {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("login")
|
|
||||||
@Deprecated
|
|
||||||
public Object loginPage() {
|
|
||||||
AuthorizationEndpoint endpoint = new AuthorizationEndpoint(realm, event);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint.legacy(OIDCLoginProtocol.CODE_PARAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("login-status-iframe.html")
|
@Path("login-status-iframe.html")
|
||||||
public Object getLoginStatusIframe() {
|
public Object getLoginStatusIframe() {
|
||||||
LoginStatusIframeEndpoint endpoint = new LoginStatusIframeEndpoint(realm);
|
LoginStatusIframeEndpoint endpoint = new LoginStatusIframeEndpoint(realm);
|
||||||
|
@ -164,45 +143,6 @@ public class OIDCLoginProtocolService {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("grants/access")
|
|
||||||
@Deprecated
|
|
||||||
public Object grantAccessToken() {
|
|
||||||
TokenEndpoint endpoint = new TokenEndpoint(tokenManager, realm, event);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint.legacy(OAuth2Constants.PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("refresh")
|
|
||||||
@Deprecated
|
|
||||||
public Object refreshAccessToken() {
|
|
||||||
TokenEndpoint endpoint = new TokenEndpoint(tokenManager, realm, event);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint.legacy(OAuth2Constants.REFRESH_TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("access/codes")
|
|
||||||
@Deprecated
|
|
||||||
public Object accessCodeToToken() {
|
|
||||||
TokenEndpoint endpoint = new TokenEndpoint(tokenManager, realm, event);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint.legacy(OAuth2Constants.AUTHORIZATION_CODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link TokenIntrospectionEndpoint#introspect()} instead
|
|
||||||
* @param tokenString
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Path("validate")
|
|
||||||
@Deprecated
|
|
||||||
public Object validateAccessToken(@QueryParam("access_token") String tokenString) {
|
|
||||||
logger.warnv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
|
|
||||||
ValidateTokenEndpoint endpoint = new ValidateTokenEndpoint(tokenManager, realm, event);
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("certs")
|
@Path("certs")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
|
|
@ -60,8 +60,6 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
|
||||||
private String nonce;
|
private String nonce;
|
||||||
private String idpHint;
|
private String idpHint;
|
||||||
|
|
||||||
private String legacyResponseType;
|
|
||||||
|
|
||||||
public AuthorizationEndpoint(RealmModel realm, EventBuilder event) {
|
public AuthorizationEndpoint(RealmModel realm, EventBuilder event) {
|
||||||
super(realm, event);
|
super(realm, event);
|
||||||
event.event(EventType.LOGIN);
|
event.event(EventType.LOGIN);
|
||||||
|
@ -102,15 +100,6 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
|
||||||
throw new RuntimeException("Unknown action " + action);
|
throw new RuntimeException("Unknown action " + action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public AuthorizationEndpoint legacy(String legacyResponseType) {
|
|
||||||
logger.warnv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
|
|
||||||
this.legacyResponseType = legacyResponseType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthorizationEndpoint register() {
|
public AuthorizationEndpoint register() {
|
||||||
event.event(EventType.REGISTER);
|
event.event(EventType.REGISTER);
|
||||||
action = Action.REGISTER;
|
action = Action.REGISTER;
|
||||||
|
@ -181,12 +170,8 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
|
||||||
|
|
||||||
private void checkResponseType() {
|
private void checkResponseType() {
|
||||||
if (responseType == null) {
|
if (responseType == null) {
|
||||||
if (legacyResponseType != null) {
|
event.error(Errors.INVALID_REQUEST);
|
||||||
responseType = legacyResponseType;
|
throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
|
||||||
} else {
|
|
||||||
event.error(Errors.INVALID_REQUEST);
|
|
||||||
throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event.detail(Details.RESPONSE_TYPE, responseType);
|
event.detail(Details.RESPONSE_TYPE, responseType);
|
||||||
|
|
|
@ -83,8 +83,6 @@ public class TokenEndpoint {
|
||||||
|
|
||||||
private String grantType;
|
private String grantType;
|
||||||
|
|
||||||
private String legacyGrantType;
|
|
||||||
|
|
||||||
public TokenEndpoint(TokenManager tokenManager, RealmModel realm, EventBuilder event) {
|
public TokenEndpoint(TokenManager tokenManager, RealmModel realm, EventBuilder event) {
|
||||||
this.tokenManager = tokenManager;
|
this.tokenManager = tokenManager;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
|
@ -132,15 +130,6 @@ public class TokenEndpoint {
|
||||||
return Cors.add(request, Response.ok()).auth().preflight().build();
|
return Cors.add(request, Response.ok()).auth().preflight().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public TokenEndpoint legacy(String legacyGrantType) {
|
|
||||||
logger.warnv("Invoking deprecated endpoint {0}", uriInfo.getRequestUri());
|
|
||||||
this.legacyGrantType = legacyGrantType;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkSsl() {
|
private void checkSsl() {
|
||||||
if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
|
if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
|
||||||
throw new ErrorResponseException("invalid_request", "HTTPS required", Response.Status.FORBIDDEN);
|
throw new ErrorResponseException("invalid_request", "HTTPS required", Response.Status.FORBIDDEN);
|
||||||
|
@ -165,11 +154,7 @@ public class TokenEndpoint {
|
||||||
|
|
||||||
private void checkGrantType() {
|
private void checkGrantType() {
|
||||||
if (grantType == null) {
|
if (grantType == null) {
|
||||||
if (legacyGrantType != null) {
|
throw new ErrorResponseException("invalid_request", "Missing form parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
|
||||||
grantType = legacyGrantType;
|
|
||||||
} else {
|
|
||||||
throw new ErrorResponseException("invalid_request", "Missing form parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grantType.equals(OAuth2Constants.AUTHORIZATION_CODE)) {
|
if (grantType.equals(OAuth2Constants.AUTHORIZATION_CODE)) {
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
package org.keycloak.protocol.oidc.endpoints;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
|
||||||
import org.keycloak.common.ClientConnection;
|
|
||||||
import org.keycloak.OAuth2Constants;
|
|
||||||
import org.keycloak.OAuthErrorException;
|
|
||||||
import org.keycloak.RSATokenVerifier;
|
|
||||||
import org.keycloak.events.Details;
|
|
||||||
import org.keycloak.events.Errors;
|
|
||||||
import org.keycloak.events.EventBuilder;
|
|
||||||
import org.keycloak.events.EventType;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.protocol.oidc.TokenManager;
|
|
||||||
import org.keycloak.representations.AccessToken;
|
|
||||||
import org.keycloak.services.ErrorResponseException;
|
|
||||||
import org.keycloak.services.Urls;
|
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.core.*;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link TokenIntrospectionEndpoint} instead
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class ValidateTokenEndpoint {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ValidateTokenEndpoint.class);
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private KeycloakSession session;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private ClientConnection clientConnection;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private UriInfo uriInfo;
|
|
||||||
|
|
||||||
@Context
|
|
||||||
private HttpHeaders headers;
|
|
||||||
|
|
||||||
private TokenManager tokenManager;
|
|
||||||
private RealmModel realm;
|
|
||||||
private EventBuilder event;
|
|
||||||
|
|
||||||
public ValidateTokenEndpoint(TokenManager tokenManager, RealmModel realm, EventBuilder event) {
|
|
||||||
this.tokenManager = tokenManager;
|
|
||||||
this.realm = realm;
|
|
||||||
this.event = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate encoded access token.
|
|
||||||
*
|
|
||||||
* @param tokenString
|
|
||||||
* @return Unmarshalled token
|
|
||||||
*/
|
|
||||||
@GET
|
|
||||||
@NoCache
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public Response validateAccessToken(@QueryParam("access_token") String tokenString) {
|
|
||||||
checkSsl();
|
|
||||||
|
|
||||||
event.event(EventType.VALIDATE_ACCESS_TOKEN);
|
|
||||||
AccessToken token = null;
|
|
||||||
try {
|
|
||||||
token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
Map<String, String> err = new HashMap<String, String>();
|
|
||||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
|
||||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Token invalid");
|
|
||||||
logger.error("Invalid token. Token verification failed.");
|
|
||||||
event.error(Errors.INVALID_TOKEN);
|
|
||||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
event.user(token.getSubject()).session(token.getSessionState()).detail(Details.VALIDATE_ACCESS_TOKEN, token.getId());
|
|
||||||
|
|
||||||
try {
|
|
||||||
tokenManager.validateToken(session, uriInfo, clientConnection, realm, token, headers);
|
|
||||||
} catch (OAuthErrorException e) {
|
|
||||||
Map<String, String> error = new HashMap<String, String>();
|
|
||||||
error.put(OAuth2Constants.ERROR, e.getError());
|
|
||||||
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
|
|
||||||
event.error(Errors.INVALID_TOKEN);
|
|
||||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build();
|
|
||||||
}
|
|
||||||
event.success();
|
|
||||||
|
|
||||||
return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkSsl() {
|
|
||||||
if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
|
|
||||||
throw new ErrorResponseException("invalid_request", "HTTPS required", Response.Status.FORBIDDEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -400,65 +400,6 @@ public class AccessTokenTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidateAccessToken() throws Exception {
|
|
||||||
Client client = ClientBuilder.newClient();
|
|
||||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
|
||||||
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
|
||||||
WebTarget grantTarget = client.target(grantUri);
|
|
||||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
|
||||||
URI validateUri = OIDCLoginProtocolService.validateAccessTokenUrl(builder).build("test");
|
|
||||||
WebTarget validateTarget = client.target(validateUri);
|
|
||||||
|
|
||||||
{
|
|
||||||
Response response = validateTarget.queryParam("access_token", "bad token").request().get();
|
|
||||||
Assert.assertEquals(400, response.getStatus());
|
|
||||||
HashMap<String, String> error = response.readEntity(new GenericType<HashMap<String, String>>() {
|
|
||||||
});
|
|
||||||
Assert.assertNotNull(error.get("error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
|
|
||||||
{
|
|
||||||
Response response = executeGrantAccessTokenRequest(grantTarget);
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
AccessToken token = response.readEntity(AccessToken.class);
|
|
||||||
Assert.assertNotNull(token);
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
|
||||||
URI logoutUri = OIDCLoginProtocolService.logoutUrl(builder).build("test");
|
|
||||||
String header = BasicAuthHelper.createHeader("test-app", "password");
|
|
||||||
Form form = new Form();
|
|
||||||
form.param("refresh_token", tokenResponse.getRefreshToken());
|
|
||||||
Response response = client.target(logoutUri).request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, header)
|
|
||||||
.post(Entity.form(form));
|
|
||||||
Assert.assertEquals(204, response.getStatus());
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
|
||||||
Assert.assertEquals(400, response.getStatus());
|
|
||||||
HashMap<String, String> error = response.readEntity(new GenericType<HashMap<String, String>>() {
|
|
||||||
});
|
|
||||||
Assert.assertNotNull(error.get("error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
client.close();
|
|
||||||
events.clear();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGrantAccessToken() throws Exception {
|
public void testGrantAccessToken() throws Exception {
|
||||||
Client client = ClientBuilder.newClient();
|
Client client = ClientBuilder.newClient();
|
||||||
|
|
Loading…
Reference in a new issue