SONAR-6856 : Add a new API ExternalGroupsProvider.doGetGroups(Context context) to allow plugins to pass groups information to SonarQube

Addition of one more api in ExternalGroupsProvider which will pass Context as parameter .
doGetGroups(String username) is marked as deprecated

Default implementation is provided in both version of doGetGroups so that authentication plugin relying on previous version ( <5.2) and current version 5.2 do not face compact issue on the SonarQube server 5.2

Testing:
1. Unit test for ExternalGroupsProvider is added.
2. Testing of authentication plugin (e.g. LDAP) targeting SonarQube Plugin apis version < 5.2 working with SonarQube server 5.2
3. Testing of LDAP plugin with SSO changes which are tareting SonarQube plugin api version 5.2 working with SonarQube server 5.2
This commit is contained in:
Sulabh Upadhyay 2015-09-22 15:58:26 +05:30 committed by Simon Brandhof
parent c769d5e095
commit 271e2cde31
3 changed files with 148 additions and 7 deletions

View File

@ -76,7 +76,7 @@ class PluginRealm
if @java_authenticator
context = org.sonar.api.security.Authenticator::Context.new(username, password, servlet_request)
status = @java_authenticator.doAuthenticate(context)
status ? synchronize(username, password, details) : nil
status ? synchronize(username, password, details, servlet_request) : nil
else
# No authenticator
nil
@ -114,7 +114,7 @@ class PluginRealm
# Authentication in external system was successful - replicate password, details and groups into Sonar
# Return the user.
#
def synchronize(username, password, details)
def synchronize(username, password, details, servlet_request)
username=details.getName() if username.blank? && details
user = User.find_by_login(username)
@ -159,7 +159,7 @@ class PluginRealm
# Note that validation disabled
user.save(false)
synchronize_groups(user)
synchronize_groups(user, servlet_request)
# Note that validation disabled
user.save(false)
end
@ -172,10 +172,11 @@ class PluginRealm
user
end
def synchronize_groups(user)
def synchronize_groups(user, servlet_request)
if @java_groups_provider
begin
groups = @java_groups_provider.doGetGroups(user.login)
provider_context = org.sonar.api.security.ExternalGroupsProvider::Context.new(user.login, servlet_request)
groups = @java_groups_provider.doGetGroups(provider_context)
rescue Exception => e
Rails.logger.error("Error from external groups provider: #{e.message}")
else

View File

@ -20,19 +20,52 @@
package org.sonar.api.security;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
/**
* Note that prefix "do" for names of methods is reserved for future enhancements, thus should not be used in subclasses.
*
* @since 2.14
* @see SecurityRealm
* @since 2.14
*/
public abstract class ExternalGroupsProvider {
/**
* @return list of groups associated with specified user, or null if such user doesn't exist
* @throws RuntimeException in case of unexpected error such as connection failure
* @deprecated replaced by {@link #doGetGroups(org.sonar.api.security.ExternalGroupsProvider.Context)} since v. 5.2
*/
public abstract Collection<String> doGetGroups(String username);
@Deprecated
public Collection<String> doGetGroups(String username) {
return null;
}
/**
* Override this method in order to load user group information.
*
* @return list of groups associated with specified user, or null if such user doesn't exist
* @throws RuntimeException in case of unexpected error such as connection failure
* @since 5.2
*/
public Collection<String> doGetGroups(Context context) {
return doGetGroups(context.getUsername());
}
public static final class Context {
private String username;
private HttpServletRequest request;
public Context(String username, HttpServletRequest request) {
this.username = username;
this.request = request;
}
public String getUsername() {
return username;
}
public HttpServletRequest getRequest() {
return request;
}
}
}

View File

@ -0,0 +1,107 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.security;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
public class ExternalGroupsProviderTest {
@Test
public void doGetGroupsNoOverride() {
ExternalGroupsProvider groupsProvider = new ExternalGroupsProvider() {
};
String userName = "foo";
assertThat(groupsProvider.doGetGroups(userName)).isNull();
assertThat(groupsProvider.doGetGroups(new ExternalGroupsProvider.Context(userName,
mock(HttpServletRequest.class)))).isNull();
}
@Test
public void doGetGroupsTests() {
final Map<String, Collection<String>> userGroupsMap = getTestUserGroupMapping();
ExternalGroupsProvider groupsProvider = new ExternalGroupsProvider() {
@Override
public Collection<String> doGetGroups(Context context) {
Preconditions.checkNotNull(context.getUsername());
Preconditions.checkNotNull(context.getRequest());
return userGroupsMap.get(context.getUsername());
}
};
runDoGetGroupsTests(groupsProvider, userGroupsMap);
}
@Test
public void doGetGroupsDeprecatedApi() {
final Map<String, Collection<String>> userGroupsMap = getTestUserGroupMapping();
ExternalGroupsProvider groupsProvider = new ExternalGroupsProvider() {
@Override
public Collection<String> doGetGroups(String username) {
Preconditions.checkNotNull(username);
return userGroupsMap.get(username);
}
};
runDoGetGroupsTests(groupsProvider, userGroupsMap);
}
private static void runDoGetGroupsTests(ExternalGroupsProvider groupsProvider, Map<String, Collection<String>> userGroupsMap) {
for (Map.Entry<String, Collection<String>> userGroupMapEntry : userGroupsMap.entrySet()) {
Collection<String> groups = groupsProvider.doGetGroups(new ExternalGroupsProvider.Context(
userGroupMapEntry.getKey(), mock(HttpServletRequest.class)));
assertThat(groups).isEqualTo(userGroupMapEntry.getValue());
}
}
private static Map<String, Collection<String>> getTestUserGroupMapping() {
Map<String, Collection<String>> userGroupsMap = new HashMap<String, Collection<String>>();
addUserGroupMapping(userGroupsMap, "userWithOneGroups", new String[] {"group1"});
addUserGroupMapping(userGroupsMap, "userWithTwoGroups", new String[] {"group1", "group2"});
addUserGroupMapping(userGroupsMap, "userWithNoGroup", new String[] {});
addUserGroupMapping(userGroupsMap, "userWithNullGroup", null);
return userGroupsMap;
}
private static void addUserGroupMapping(Map<String, Collection<String>> userGroupsMap, String user, @Nullable String[] groups) {
Collection<String> groupsCollection = null;
if (groups != null) {
groupsCollection = new ArrayList<String>();
groupsCollection.addAll(Arrays.asList(groups));
}
userGroupsMap.put(user, groupsCollection);
}
}