[KEYCLOAK-8901] - Identity Provider : UserInfo response as JWT Token not supported

This commit is contained in:
Pedro Igor 2018-12-04 14:16:54 -02:00
parent b5d2b23d02
commit e798c3bca2
2 changed files with 117 additions and 12 deletions

View file

@ -55,7 +55,7 @@ import org.keycloak.util.JsonSerialization;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@ -378,20 +378,29 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
if (userInfoUrl != null && !userInfoUrl.isEmpty() && (id == null || name == null || preferredUsername == null || email == null)) {
if (accessToken != null) {
SimpleHttp.Response response = SimpleHttp.doGet(userInfoUrl, session)
.header("Authorization", "Bearer " + accessToken).asResponse();
if (response.getStatus() != 200) {
String msg = "failed to invoke user info url";
SimpleHttp.Response response = executeRequest(userInfoUrl, SimpleHttp.doGet(userInfoUrl, session).header("Authorization", "Bearer " + accessToken));
String contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
JsonNode userInfo;
if (MediaType.APPLICATION_JSON.equals(contentType)) {
userInfo = response.asJson();
} else if ("application/jwt".equals(contentType)) {
JWSInput jwsInput;
try {
String tmp = response.asString();
if (tmp != null) msg = tmp;
} catch (IOException e) {
jwsInput = new JWSInput(response.asString());
} catch (JWSInputException cause) {
throw new RuntimeException("Failed to parse JWT userinfo response", cause);
}
throw new IdentityBrokerException("Failed to invoke on user info url: " + msg);
if (verify(jwsInput)) {
userInfo = JsonSerialization.readValue(jwsInput.getContent(), JsonNode.class);
} else {
throw new RuntimeException("Failed to verify signature of userinfo response from [" + userInfoUrl + "].");
}
} else {
throw new RuntimeException("Unsupported content-type [" + contentType + "] in response from [" + userInfoUrl + "].");
}
JsonNode userInfo = response.asJson();
id = getJsonProperty(userInfo, "sub");
name = getJsonProperty(userInfo, "name");
@ -434,6 +443,21 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
return getConfig().getUserInfoUrl();
}
private SimpleHttp.Response executeRequest(String url, SimpleHttp request) throws IOException {
SimpleHttp.Response response = request.asResponse();
if (response.getStatus() != 200) {
String msg = "failed to invoke url [" + url + "]";
try {
String tmp = response.asString();
if (tmp != null) msg = tmp;
} catch (IOException e) {
}
throw new IdentityBrokerException("Failed to invoke url [" + url + "]: " + msg);
}
return response;
}
private String verifyAccessToken(AccessTokenResponse tokenResponse) {
String accessToken = tokenResponse.getToken();

View file

@ -1,9 +1,27 @@
package org.keycloak.testsuite.broker;
import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME;
import static org.keycloak.testsuite.broker.BrokerTestTools.getAuthRoot;
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
import java.util.List;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.IdentityProviderResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
import org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper;
import org.keycloak.crypto.Algorithm;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.Assert;
public class KcOidcBrokerTest extends AbstractBrokerTest {
@ -32,4 +50,67 @@ public class KcOidcBrokerTest extends AbstractBrokerTest {
return Lists.newArrayList(attrMapper1, attrMapper2);
}
@Test
public void loginFetchingUserFromUserEndpoint() {
RealmResource realm = realmsResouce().realm(bc.providerRealmName());
ClientsResource clients = realm.clients();
ClientRepresentation brokerApp = clients.findByClientId("brokerapp").get(0);
try {
IdentityProviderResource identityProviderResource = realmsResouce().realm(bc.consumerRealmName()).identityProviders().get(bc.getIDPAlias());
IdentityProviderRepresentation idp = identityProviderResource.toRepresentation();
idp.getConfig().put(OIDCIdentityProviderConfig.JWKS_URL, getAuthRoot(suiteContext) + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/certs");
identityProviderResource.update(idp);
brokerApp.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, Algorithm.RS256);
brokerApp.getAttributes().put("validateSignature", Boolean.TRUE.toString());
clients.get(brokerApp.getId()).update(brokerApp);
driver.navigate().to(getAccountUrl(bc.consumerRealmName()));
log.debug("Clicking social " + bc.getIDPAlias());
accountLoginPage.clickSocial(bc.getIDPAlias());
waitForPage(driver, "log in to", true);
Assert.assertTrue("Driver should be on the provider realm page right now",
driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
log.debug("Logging in");
accountLoginPage.login(bc.getUserLogin(), bc.getUserPassword());
waitForPage(driver, "update account information", false);
updateAccountInformationPage.assertCurrent();
Assert.assertTrue("We must be on correct realm right now",
driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/"));
log.debug("Updating info on updateAccount page");
updateAccountInformationPage.updateAccountInformation(bc.getUserLogin(), bc.getUserEmail(), "Firstname", "Lastname");
UsersResource consumerUsers = adminClient.realm(bc.consumerRealmName()).users();
int userCount = consumerUsers.count();
Assert.assertTrue("There must be at least one user", userCount > 0);
List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
boolean isUserFound = false;
for (UserRepresentation user : users) {
if (user.getUsername().equals(bc.getUserLogin()) && user.getEmail().equals(bc.getUserEmail())) {
isUserFound = true;
break;
}
}
Assert.assertTrue("There must be user " + bc.getUserLogin() + " in realm " + bc.consumerRealmName(),
isUserFound);
} finally {
brokerApp.getAttributes().put(OIDCConfigAttributes.USER_INFO_RESPONSE_SIGNATURE_ALG, null);
brokerApp.getAttributes().put("validateSignature", Boolean.FALSE.toString());
clients.get(brokerApp.getId()).update(brokerApp);
}
}
}