KEYCLOAK-17179 IdP mappers with MultiValued property can't be saved
This commit is contained in:
parent
91865fa93e
commit
07d57ca30f
8 changed files with 282 additions and 16 deletions
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.broker.provider;
|
||||
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Testing IdP mapper with multivalued property
|
||||
*
|
||||
* @author Martin Bartos <mabartos@redhat.com>
|
||||
*/
|
||||
public class MultiValuedTestIdPMapper extends AbstractIdentityProviderMapper {
|
||||
public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER};
|
||||
|
||||
public static final String PROVIDER_ID = "multi-valued-test-idp-mapper";
|
||||
public static final String VALUES_ATTRIBUTE = "values";
|
||||
|
||||
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(VALUES_ATTRIBUTE);
|
||||
property.setLabel("Test values");
|
||||
property.setHelpText("Define test values");
|
||||
property.setType(ProviderConfigProperty.MULTIVALUED_STRING_TYPE);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCompatibleProviders() {
|
||||
return COMPATIBLE_PROVIDERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return "Test IdP Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Test MultiValued Mapper";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "This is testing IdP mapper with multivalued property";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
# and other contributors as indicated by the @author tags.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.keycloak.testsuite.broker.provider.MultiValuedTestIdPMapper
|
|
@ -580,9 +580,9 @@ public class IdentityProviderTest extends AbstractAdminTest {
|
|||
expected.add("hardcoded-user-session-attribute-idp-mapper");
|
||||
expected.add("oidc-hardcoded-role-idp-mapper");
|
||||
expected.add("hardcoded-attribute-idp-mapper");
|
||||
for (String id: mapperIds) {
|
||||
expected.add(id);
|
||||
}
|
||||
expected.add("multi-valued-test-idp-mapper");
|
||||
expected.addAll(Arrays.asList(mapperIds));
|
||||
|
||||
Assert.assertEquals("mapperTypes", expected, mapperTypes.keySet());
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.console.page.idp;
|
||||
package org.keycloak.testsuite.console.page.idp.mappers;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.testsuite.console.page.AdminConsoleCreate;
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.console.page.idp;
|
||||
package org.keycloak.testsuite.console.page.idp.mappers;
|
||||
|
||||
import org.keycloak.testsuite.page.Form;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
@ -34,6 +34,9 @@ public class IdentityProviderMapperForm extends Form {
|
|||
@FindBy(id = "syncMode")
|
||||
private Select syncMode;
|
||||
|
||||
@FindBy(id = "mapperTypeCreate")
|
||||
private Select mapperType;
|
||||
|
||||
public void setName(final String value) {
|
||||
setTextInputValue(name, value);
|
||||
}
|
||||
|
@ -45,4 +48,12 @@ public class IdentityProviderMapperForm extends Form {
|
|||
public String syncMode() {
|
||||
return syncMode.getFirstSelectedOption().getText();
|
||||
}
|
||||
|
||||
public void setMapperType(final String value) {
|
||||
mapperType.selectByVisibleText(value);
|
||||
}
|
||||
|
||||
public String getMapperType() {
|
||||
return mapperType.getFirstSelectedOption().getText();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.console.page.idp.mappers;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextInputValue;
|
||||
import static org.keycloak.testsuite.util.UIUtils.setTextInputValue;
|
||||
|
||||
/**
|
||||
* @author mabartos
|
||||
*/
|
||||
public class MultivaluedStringProperty {
|
||||
|
||||
@FindBy(xpath = "//input[@ng-model='config[option.name][i]']")
|
||||
private List<WebElement> items;
|
||||
|
||||
@FindBy(xpath = "//button[@data-ng-click='deleteValueFromMultivalued(option.name, $index)']")
|
||||
private List<WebElement> minusButtons;
|
||||
|
||||
@FindBy(xpath = "//button[@data-ng-click='addValueToMultivalued(option.name)']")
|
||||
private WebElement plusButton;
|
||||
|
||||
public boolean isPresent() {
|
||||
try {
|
||||
return plusButton.isDisplayed() && items != null && !items.isEmpty();
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void clickAddItem() {
|
||||
plusButton.click();
|
||||
}
|
||||
|
||||
public List<WebElement> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public String getItem(int index) {
|
||||
validateIndex(index);
|
||||
return getTextInputValue(getItems().get(index));
|
||||
}
|
||||
|
||||
public void editItem(int index, String item) {
|
||||
validateIndex(index);
|
||||
setTextInputValue(getItems().get(index), item);
|
||||
}
|
||||
|
||||
public void addItem(String item) {
|
||||
clickAddItem();
|
||||
|
||||
final List<WebElement> items = getItems();
|
||||
WebElement webElement = items.get(items.size() - 1);
|
||||
setTextInputValue(webElement, item);
|
||||
}
|
||||
|
||||
public void removeItem(int index) {
|
||||
validateIndex(index);
|
||||
if (index == getItems().size() - 1) {
|
||||
editItem(index, "");
|
||||
} else {
|
||||
minusButtons.get(index).click();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIndex(int index) {
|
||||
if (index >= getItems().size()) throw new AssertionError("Input with index: " + index + " does not exist.");
|
||||
}
|
||||
}
|
|
@ -20,18 +20,20 @@ package org.keycloak.testsuite.console.idp;
|
|||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.console.page.idp.mappers.MultivaluedStringProperty;
|
||||
import org.keycloak.testsuite.console.AbstractConsoleTest;
|
||||
import org.keycloak.testsuite.console.page.idp.CreateIdentityProvider;
|
||||
import org.keycloak.testsuite.console.page.idp.CreateIdentityProviderMapper;
|
||||
import org.keycloak.testsuite.console.page.idp.mappers.CreateIdentityProviderMapper;
|
||||
import org.keycloak.testsuite.console.page.idp.IdentityProvider;
|
||||
import org.keycloak.testsuite.console.page.idp.IdentityProviders;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -52,6 +54,9 @@ public class IdentityProviderTest extends AbstractConsoleTest {
|
|||
@Page
|
||||
private CreateIdentityProviderMapper createIdentityProviderMapperPage;
|
||||
|
||||
@Page
|
||||
private MultivaluedStringProperty multiStringPropertyForm;
|
||||
|
||||
@Before
|
||||
public void beforeIdentityProviderTest() {
|
||||
identityProvidersPage.navigateTo();
|
||||
|
@ -128,6 +133,57 @@ public class IdentityProviderTest extends AbstractConsoleTest {
|
|||
assertMapperSyncModeIsSetToImport();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIdentityProviderCustomMapper() {
|
||||
createIdentityProviderPage.setProviderId("google");
|
||||
identityProviderPage.setIds("google", "google");
|
||||
|
||||
identityProvidersPage.addProvider("google");
|
||||
assertCurrentUrlEquals(createIdentityProviderPage);
|
||||
|
||||
createIdentityProviderPage.form().setClientId("test-google");
|
||||
createIdentityProviderPage.form().setClientSecret("secret");
|
||||
|
||||
createIdentityProviderPage.form().save();
|
||||
assertAlertSuccess();
|
||||
refreshPageAndWaitForLoad();
|
||||
assertCurrentUrlEquals(identityProviderPage);
|
||||
|
||||
identityProviderPage.form().createMapper();
|
||||
createIdentityProviderMapperPage.setIdp("google");
|
||||
assertCurrentUrlEquals(createIdentityProviderMapperPage);
|
||||
createIdentityProviderMapperPage.form().setName("Multivalued Map");
|
||||
createIdentityProviderMapperPage.form().setSyncMode("import");
|
||||
createIdentityProviderMapperPage.form().setMapperType("Test MultiValued Mapper");
|
||||
|
||||
assertThat(multiStringPropertyForm.isPresent(), is(true));
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(1));
|
||||
|
||||
multiStringPropertyForm.editItem(0, "firstValue");
|
||||
assertThat(multiStringPropertyForm.getItem(0), is("firstValue"));
|
||||
|
||||
multiStringPropertyForm.addItem("second");
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(2));
|
||||
|
||||
multiStringPropertyForm.editItem(1, "secondValue");
|
||||
assertThat(multiStringPropertyForm.getItem(1), is("secondValue"));
|
||||
|
||||
multiStringPropertyForm.addItem("third");
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(3));
|
||||
|
||||
multiStringPropertyForm.removeItem(1);
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(2));
|
||||
assertThat(multiStringPropertyForm.getItem(1), is("third"));
|
||||
|
||||
createIdentityProviderMapperPage.form().save();
|
||||
assertAlertSuccess();
|
||||
|
||||
// add empty item
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(3));
|
||||
refreshPageAndWaitForLoad();
|
||||
assertThat(multiStringPropertyForm.getItems().size(), is(3));
|
||||
}
|
||||
|
||||
private void assertMapperSyncModeIsSetToImport() {
|
||||
assertEquals("import", createIdentityProviderMapperPage.form().syncMode());
|
||||
}
|
||||
|
|
|
@ -2198,14 +2198,19 @@ module.controller('IdentityProviderMapperListCtrl', function($scope, realm, iden
|
|||
$scope.mappers = mappers;
|
||||
});
|
||||
|
||||
module.controller('IdentityProviderMapperCtrl', function($scope, realm, identityProvider, mapperTypes, mapper, IdentityProviderMapper, Notifications, Dialog, $location) {
|
||||
module.controller('IdentityProviderMapperCtrl', function ($scope, realm, identityProvider, mapperTypes, mapper, IdentityProviderMapper, Notifications, Dialog, ComponentUtils, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.identityProvider = identityProvider;
|
||||
$scope.create = false;
|
||||
$scope.mapper = angular.copy(mapper);
|
||||
$scope.changed = false;
|
||||
$scope.mapperType = mapperTypes[mapper.identityProviderMapper];
|
||||
$scope.$watch(function() {
|
||||
|
||||
ComponentUtils.convertAllMultivaluedStringValuesToList($scope.mapperType.properties, mapper.config);
|
||||
ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.mapperType.properties, mapper.config);
|
||||
|
||||
$scope.mapper = angular.copy(mapper);
|
||||
|
||||
$scope.$watch(function () {
|
||||
return $location.path();
|
||||
}, function() {
|
||||
$scope.path = $location.path().substring(1).split("/");
|
||||
|
@ -2218,12 +2223,16 @@ module.controller('IdentityProviderMapperCtrl', function($scope, realm, identit
|
|||
}, true);
|
||||
|
||||
$scope.save = function() {
|
||||
let mapperCopy = angular.copy($scope.mapper);
|
||||
ComponentUtils.convertAllListValuesToMultivaluedString($scope.mapperType.properties, mapperCopy.config);
|
||||
|
||||
IdentityProviderMapper.update({
|
||||
realm : realm.realm,
|
||||
alias: identityProvider.alias,
|
||||
alias : identityProvider.alias,
|
||||
mapperId : mapper.id
|
||||
}, $scope.mapper, function() {
|
||||
}, mapperCopy, function () {
|
||||
$scope.changed = false;
|
||||
ComponentUtils.addLastEmptyValueToMultivaluedLists($scope.mapperType.properties, $scope.mapper.config);
|
||||
mapper = angular.copy($scope.mapper);
|
||||
$location.url("/realms/" + realm.realm + '/identity-provider-mappers/' + identityProvider.alias + "/mappers/" + mapper.id);
|
||||
Notifications.success("Your changes have been saved.");
|
||||
|
@ -2251,7 +2260,7 @@ module.controller('IdentityProviderMapperCtrl', function($scope, realm, identit
|
|||
|
||||
});
|
||||
|
||||
module.controller('IdentityProviderMapperCreateCtrl', function($scope, realm, identityProvider, mapperTypes, IdentityProviderMapper, Notifications, Dialog, $location) {
|
||||
module.controller('IdentityProviderMapperCreateCtrl', function ($scope, realm, identityProvider, mapperTypes, IdentityProviderMapper, Notifications, Dialog, ComponentUtils, $location) {
|
||||
$scope.realm = realm;
|
||||
$scope.identityProvider = identityProvider;
|
||||
$scope.create = true;
|
||||
|
@ -2268,11 +2277,15 @@ module.controller('IdentityProviderMapperCreateCtrl', function($scope, realm, id
|
|||
$scope.path = $location.path().substring(1).split("/");
|
||||
});
|
||||
|
||||
$scope.save = function() {
|
||||
$scope.save = function () {
|
||||
$scope.mapper.identityProviderMapper = $scope.mapperType.id;
|
||||
let copyMapper = angular.copy($scope.mapper);
|
||||
ComponentUtils.convertAllListValuesToMultivaluedString($scope.mapperType.properties, copyMapper.config);
|
||||
|
||||
IdentityProviderMapper.save({
|
||||
realm : realm.realm, alias: identityProvider.alias
|
||||
}, $scope.mapper, function(data, headers) {
|
||||
realm : realm.realm,
|
||||
alias : identityProvider.alias
|
||||
}, copyMapper, function (data, headers) {
|
||||
var l = headers().location;
|
||||
var id = l.substring(l.lastIndexOf("/") + 1);
|
||||
$location.url("/realms/" + realm.realm + '/identity-provider-mappers/' + identityProvider.alias + "/mappers/" + id);
|
||||
|
|
Loading…
Reference in a new issue