mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-06 03:49:52 +02:00
implement user converter
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@@ -33,10 +33,14 @@ import sonia.scm.NotFoundException;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.user.ExternalUserConverter;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.security.AdministrationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class for syncing realms. The class should simplify the creation of realms, which are syncing authenticated
|
||||
* users with the local database.
|
||||
@@ -50,28 +54,41 @@ public final class SyncingRealmHelper {
|
||||
private final AdministrationContext ctx;
|
||||
private final UserManager userManager;
|
||||
private final GroupManager groupManager;
|
||||
private final Set<ExternalUserConverter> externalUserConverters;
|
||||
|
||||
/**
|
||||
* Constructs a new SyncingRealmHelper.
|
||||
*
|
||||
* @param ctx administration context
|
||||
* @param userManager user manager
|
||||
* @param groupManager group manager
|
||||
* @param ctx administration context
|
||||
* @param userManager user manager
|
||||
* @param groupManager group manager
|
||||
* @param externalUserConverters global scm configuration
|
||||
*/
|
||||
@Inject
|
||||
public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager) {
|
||||
public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager, Set<ExternalUserConverter> externalUserConverters) {
|
||||
this.ctx = ctx;
|
||||
this.userManager = userManager;
|
||||
this.groupManager = groupManager;
|
||||
this.externalUserConverters = externalUserConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SyncingRealmHelper.
|
||||
*
|
||||
* @param ctx administration context
|
||||
* @param userManager user manager
|
||||
* @param groupManager group manager
|
||||
*/
|
||||
@Deprecated
|
||||
public SyncingRealmHelper(AdministrationContext ctx, UserManager userManager, GroupManager groupManager) {
|
||||
this(ctx, userManager, groupManager, Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link AuthenticationInfo} from user and groups.
|
||||
*
|
||||
*
|
||||
* @param realm name of the realm
|
||||
* @param user authenticated user
|
||||
*
|
||||
* @param user authenticated user
|
||||
* @return authentication info
|
||||
*/
|
||||
public AuthenticationInfo createAuthenticationInfo(String realm, User user) {
|
||||
@@ -114,10 +131,17 @@ public final class SyncingRealmHelper {
|
||||
public void store(final User user) {
|
||||
ctx.runAsAdmin(() -> {
|
||||
if (userManager.contains(user.getName())) {
|
||||
User clone = user.clone();
|
||||
if (!externalUserConverters.isEmpty()) {
|
||||
for (ExternalUserConverter converter : externalUserConverters) {
|
||||
clone = converter.convert(clone);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
userManager.modify(user);
|
||||
userManager.modify(clone);
|
||||
} catch (NotFoundException e) {
|
||||
throw new IllegalStateException("got NotFoundException though user " + user.getName() + " could be loaded", e);
|
||||
throw new IllegalStateException("got NotFoundException though user " + clone.getName() + " could be loaded", e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.plugin.ExtensionPoint;
|
||||
|
||||
@ExtensionPoint
|
||||
public interface ExternalUserConverter {
|
||||
|
||||
/**
|
||||
* Returns the converted user.
|
||||
*
|
||||
* @return converted user
|
||||
* @since 2.8.0
|
||||
*/
|
||||
User convert(User user);
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package sonia.scm.security;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -36,6 +37,7 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.AlreadyExistsException;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupManager;
|
||||
import sonia.scm.user.ExternalUserConverter;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserManager;
|
||||
import sonia.scm.web.security.AdministrationContext;
|
||||
@@ -47,6 +49,7 @@ import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -68,8 +71,13 @@ public class SyncingRealmHelperTest {
|
||||
@Mock
|
||||
private UserManager userManager;
|
||||
|
||||
@Mock
|
||||
private ExternalUserConverter converter;
|
||||
|
||||
private SyncingRealmHelper helper;
|
||||
|
||||
private SyncingRealmHelper helperWithConverters;
|
||||
|
||||
/**
|
||||
* Mock {@link AdministrationContext} and create object under test.
|
||||
*/
|
||||
@@ -94,6 +102,7 @@ public class SyncingRealmHelperTest {
|
||||
};
|
||||
|
||||
helper = new SyncingRealmHelper(ctx, userManager, groupManager);
|
||||
helperWithConverters = new SyncingRealmHelper(ctx, userManager, groupManager, ImmutableSet.of(converter));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +179,23 @@ public class SyncingRealmHelperTest {
|
||||
verify(userManager, times(1)).modify(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link SyncingRealmHelper#store(User)} with an existing user.
|
||||
*/
|
||||
@Test
|
||||
public void testConvertUser(){
|
||||
User zaphod = new User("zaphod");
|
||||
when(converter.convert(any())).thenReturn(zaphod);
|
||||
when(userManager.contains("tricia")).thenReturn(Boolean.TRUE);
|
||||
|
||||
User user = new User("tricia");
|
||||
|
||||
helperWithConverters.store(user);
|
||||
|
||||
verify(converter).convert(user);
|
||||
verify(userManager, times(1)).modify(zaphod);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void builderShouldSetValues() {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.user;
|
||||
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.plugin.Extension;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Extension
|
||||
public class InternalToExternalUserConverter implements ExternalUserConverter{
|
||||
|
||||
private final ScmConfiguration scmConfiguration;
|
||||
|
||||
@Inject
|
||||
public InternalToExternalUserConverter(ScmConfiguration scmConfiguration) {
|
||||
this.scmConfiguration = scmConfiguration;
|
||||
}
|
||||
|
||||
public User convert(User user) {
|
||||
if (shouldNotConvertUser(user)) {
|
||||
return user;
|
||||
}
|
||||
user.setExternal(true);
|
||||
user.setPassword(null);
|
||||
return user;
|
||||
}
|
||||
|
||||
private boolean shouldNotConvertUser(User user) {
|
||||
return user.isExternal() || !scmConfiguration.isEnabledUserConverter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.user;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class InternalToExternalUserConverterTest {
|
||||
|
||||
@Mock
|
||||
ScmConfiguration scmConfiguration;
|
||||
|
||||
@InjectMocks
|
||||
InternalToExternalUserConverter converter;
|
||||
|
||||
@Test
|
||||
void shouldNotConvertExternalUser() {
|
||||
User external = new User();
|
||||
external.setExternal(true);
|
||||
|
||||
User user = converter.convert(external);
|
||||
|
||||
assertThat(user).isSameAs(external);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotConvertIfConfigDisabled() {
|
||||
when(scmConfiguration.isEnabledUserConverter()).thenReturn(false);
|
||||
User external = new User();
|
||||
external.setExternal(false);
|
||||
|
||||
User user = converter.convert(external);
|
||||
|
||||
assertThat(user).isSameAs(external);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnConvertedUser() {
|
||||
when(scmConfiguration.isEnabledUserConverter()).thenReturn(true);
|
||||
User internal = new User();
|
||||
internal.setExternal(false);
|
||||
|
||||
User external = converter.convert(internal);
|
||||
|
||||
assertThat(external).isInstanceOf(User.class);
|
||||
assertThat(external.isExternal()).isTrue();
|
||||
assertThat(external.getPassword()).isNull();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user