Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ protected void loginThroughIdpAndLogout() {

protected void loginUser() {
logInAsUserInIDP();

updateAccountInformation();
assertUserCreatedInConsumerRealm();
}

// Reused by concrete tests that override loginUser() with a custom pre-login step (extra query
// params, IdP-hint, locale checks, etc.) but still need the same post-login assertions.
protected void assertUserCreatedInConsumerRealm() {
ManagedRealm consumerRealm = getConsumerRealm();
UserRepresentation userRep = AccountHelper.getUserRepresentation(
consumerRealm.admin(), getUserLogin());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
import java.util.List;
import java.util.Set;

import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testframework.oauth.OAuthClient;
Expand All @@ -16,6 +22,7 @@
import org.keycloak.testframework.ui.page.LoginPage;
import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;
import org.keycloak.testsuite.util.AccountHelper;
import org.keycloak.testsuite.util.userprofile.UserProfileUtil;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -71,6 +78,44 @@ void relaxProviderProfileVerification() {
}
}

// Tests that map custom claims onto user attributes (e.g. IdP mappers writing a non-standard
// attribute) need the declarative user profile to accept attributes outside its managed schema,
// otherwise they're silently dropped when the user is created or later updated (e.g. by the
// first-broker-login review-profile form).
@BeforeEach
void enableUnmanagedAttributes() {
UserProfileUtil.enableUnmanagedAttributes(getConsumerRealm().admin().users().userProfile());
UserProfileUtil.enableUnmanagedAttributes(getProviderRealm().admin().users().userProfile());
}
Comment thread
sguilhen marked this conversation as resolved.
Resolved

// Turns off the first-broker-login review-profile step for flows that want to test something else
// without the review-profile page interrupting the redirect back to the consumer. Disabling the flow
// execution alone isn't enough: the new-testsuite consumer realm enables the VERIFY_PROFILE required
// action by default, which would still intercept the incomplete imported user (the provider user has
// no first/last name on purpose), so that is disabled too, mirroring the legacy suite (which never
// enabled VERIFY_PROFILE at all).
protected void disableUpdateProfileOnFirstLogin() {
var flows = getConsumerRealm().admin().flows();
for (AuthenticationExecutionInfoRepresentation execution :
flows.getExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW)) {
if (IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID.equals(execution.getProviderId())) {
execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name());
flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution);
} else if (execution.getAlias() != null
&& execution.getAlias().equals(DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS)) {
AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig());
config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_OFF);
flows.updateAuthenticatorConfig(config.getId(), config);
}
}
for (RequiredActionProviderRepresentation action : getConsumerRealm().admin().flows().getRequiredActions()) {
if (UserModel.RequiredAction.VERIFY_PROFILE.name().equals(action.getAlias())) {
action.setEnabled(false);
getConsumerRealm().admin().flows().updateRequiredAction(action.getAlias(), action);
}
}
}

protected String getUserLogin() {
return USER_LOGIN;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.keycloak.tests.broker;
package org.keycloak.tests.broker.saml;

import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.tests.broker.AbstractKcSamlBrokerTest;

@KeycloakIntegrationTest
public class KcSamlBrokerTest extends AbstractKcSamlBrokerTest {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.keycloak.tests.broker.saml;

import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyUse;
import org.keycloak.protocol.saml.SamlConfigAttributes;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.KeysMetadataRepresentation.KeyMetadataRepresentation;
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
import org.keycloak.testframework.realm.ManagedRealm;
import org.keycloak.tests.broker.AbstractKcSamlBrokerTest;

import org.junit.jupiter.api.BeforeEach;

@KeycloakIntegrationTest
public class KcSamlSignedDocumentOnlyBrokerTest extends AbstractKcSamlBrokerTest {

@BeforeEach
void configureSignedDocumentOnly() {
String providerSigningCert = activeRs256SigCert(providerRealm);
String consumerSigningCert = activeRs256SigCert(consumerRealm);

String samlClientId = "http://localhost:8080/realms/" + CONSUMER_REALM;
Comment thread
sguilhen marked this conversation as resolved.
Resolved
ClientRepresentation client = providerRealm.admin().clients().findByClientId(samlClientId).get(0);
client.getAttributes().put(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, "false");
client.getAttributes().put(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true");
client.getAttributes().put(SamlConfigAttributes.SAML_SIGNATURE_ALGORITHM, "RSA_SHA256");
// Require and validate the consumer's signature on incoming AuthnRequests.
client.getAttributes().put(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE, "true");
client.getAttributes().put(SamlConfigAttributes.SAML_SIGNING_CERTIFICATE_ATTRIBUTE, consumerSigningCert);
Comment on lines +25 to +31
providerRealm.admin().clients().get(client.getId()).update(client);

IdentityProviderRepresentation idp = consumerRealm.admin()
.identityProviders().get(getIdpAlias()).toRepresentation();
idp.getConfig().put(SAMLIdentityProviderConfig.VALIDATE_SIGNATURE, "true");
idp.getConfig().put(SAMLIdentityProviderConfig.WANT_ASSERTIONS_SIGNED, "false");
idp.getConfig().put(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, providerSigningCert);
// Sign the AuthnRequests sent to the provider so it can validate them.
idp.getConfig().put(SAMLIdentityProviderConfig.WANT_AUTHN_REQUESTS_SIGNED, "true");
consumerRealm.admin().identityProviders().get(getIdpAlias()).update(idp);
}

private static String activeRs256SigCert(ManagedRealm realm) {
return realm.admin().keys().getKeyMetadata().getKeys().stream()
.filter(k -> k.getCertificate() != null && KeyUse.SIG.equals(k.getUse())
&& Algorithm.RS256.equals(k.getAlgorithm()))
.map(KeyMetadataRepresentation::getCertificate)
.findFirst().orElseThrow();
}
}

This file was deleted.

Loading