Skip to content

Commit 7f7035d

Browse files
imduffy15Abhinandan Prateek
authored andcommitted
Update unit tests, add filter to list all users, update ssl
Signed-off-by: Abhinandan Prateek <aprateek@apache.org>
1 parent 25e8e9b commit 7f7035d

29 files changed

Lines changed: 1072 additions & 875 deletions

client/tomcatconf/commands.properties.in

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,9 +666,8 @@ listDedicatedClusters=1
666666
listDedicatedHosts=1
667667

668668
### LDAP
669-
searchLdap=3
670669
listLdapConfigurations=15
671670
addLdapConfiguration=3
672671
deleteLdapConfiguration=3
673-
listAllLdapUsers=3
672+
listLdapUsers=3
674673
ldapCreateAccount=3

docs/en-US/LDAP-for-user-authentication.xml

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,28 @@
2424
<section id="LDAP-for-user-authentication">
2525
<title>Using an LDAP Server for User Authentication</title>
2626
<para>You can use an external LDAP server such as Microsoft Active Directory or OpenLDAP to authenticate &PRODUCT; end-users.</para>
27-
<para>To set up LDAP authentication in &PRODUCT;, open the global settings page and set:</para>
27+
<para>In order to do this you must:</para>
2828
<itemizedlist>
29-
<listitem><para>ldap.basedn - The base directory you want to search within for uses</para></listitem>
30-
<listitem><para>ldap.bind.password - The password you wish to use to bind, this can be blank if the server supports anonymous binding</para></listitem>
31-
<listitem><para>ldap.bind.principal - The account you wish to use to bind, this can be blank if the server supports anonymous binding</para></listitem>
32-
<listitem><para>ldap.email.attribute - The attribute within your LDAP server that holds a value for users email address</para></listitem>
33-
<listitem><para>ldap.realname.attribute - The attribute within your LDAP server that holds a value users realname</para></listitem>
34-
<listitem><para>ldap.user.object - The object class that identifies a user</para></listitem>
35-
<listitem><para>ldap.username.attribute - The attribute within your LDAP server that has a value that will match the cloudstack accounts username field</para></listitem>
29+
<listitem><para>Set your LDAP configuration within &PRODUCT;</para></listitem>
30+
<listitem><para>Create &PRODUCT; accounts for LDAP users</para></listitem>
3631
</itemizedlist>
37-
<para>Finally you can add LDAP servers from Global Settings -> Select View -> LDAP Configuration. This requires a hostname and port</para>
32+
<para>To set up LDAP authentication in &PRODUCT;, open the global settings page and search for LDAP</para>
33+
<para>Set ldap.basedn to match your sever's base directory.</para>
34+
<para>Review the defaults for the following, ensure that they match your schema.</para>
35+
<itemizedlist>
36+
<listitem><para>ldap.email.attribute</para></listitem>
37+
<listitem><para>ldap.firstname.attribute</para></listitem>
38+
<listitem><para>ldap.lastname.attribute</para></listitem>
39+
<listitem><para>ldap.username.attribute</para></listitem>
40+
<listitem><para>ldap.user.object</para></listitem>
41+
</itemizedlist>
42+
<para>Optionally you can set the following:</para>
43+
<itemizedlist>
44+
<listitem><para>If you do not want to use anonymous binding you can set ldap.bind.principle and ldap.bind.password as credentials for your LDAP server that will grant &PRODUCT; permission to perform a search on the LDAP server.</para></listitem>
45+
<listitem><para>For SSL support set ldap.truststore to a path on the file system where your trusted store is located. Along with this set ldap.truststore.password as the password that unlocks the truststore.</para></listitem>
46+
<listitem><para>If you wish to filter down the user set that is granted access to &PRODUCT; via the LDAP attribute memberof you can do so using ldap.search.group.principle.</para></listitem>
47+
</itemizedlist>
48+
<para>Finally, you can add your LDAP server. To do so select LDAP Configuration from the views section within global settings. Click on "Configure LDAP" and fill in your server's hostname and port.</para>
3849
<xi:include href="example-activedirectory-configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
3950
<xi:include href="example-openldap-configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
40-
<!-- Support for SSL has been removed but will be back shortly. -->
41-
<!-- <xi:include href="SSL-keystore-path-and-password.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> -->
4251
</section>

docs/en-US/example-activedirectory-configuration.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424

2525
<section id="example-activedirectory-configuration">
2626
<title>Example LDAP Configuration for Active Directory</title>
27-
<para>This shows the configuration settings required for using ActiveDirectory</para>
27+
<para>This shows the configuration settings required for using ActiveDirectory.</para>
2828
<itemizedlist>
2929
<listitem><para>samAccountName - Logon name</para></listitem>
3030
<listitem><para>mail - Email Address</para></listitem>
3131
<listitem><para>cn - Real name</para></listitem>
3232
</itemizedlist>
3333
<para>Along with this the ldap.user.object name needs to be modified, by default ActiveDirectory uses the value "user" for this.</para>
34-
<para>Map the following attributes accordingly as shown below within the cloudstack ldap configuration:</para>
34+
<para>Map the following attributes accordingly as shown below:</para>
3535
<mediaobject>
3636
<imageobject>
3737
<imagedata fileref="./images/add-ldap-configuration-ad.png"/>

docs/en-US/example-openldap-configuration.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424

2525
<section id="example-openldap-configuration">
2626
<title>Example LDAP Configuration for OpenLdap</title>
27-
<para>This shows the configuration settings required for using OpenLDAP</para>
28-
<para>The default values supplied are suited for OpenLDAP</para>
27+
<para>This shows the configuration settings required for using OpenLDAP.</para>
28+
<para>The default values supplied are suited for OpenLDAP.</para>
2929
<itemizedlist>
3030
<listitem><para>uid - Logon name</para></listitem>
3131
<listitem><para>mail - Email Address</para></listitem>

plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccount.java renamed to plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapCreateAccountCmd.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@
4242
import com.cloud.user.UserAccount;
4343

4444
@APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0")
45-
public class LdapCreateAccount extends BaseCmd {
45+
public class LdapCreateAccountCmd extends BaseCmd {
4646
public static final Logger s_logger = Logger
47-
.getLogger(LdapCreateAccount.class.getName());
47+
.getLogger(LdapCreateAccountCmd.class.getName());
4848
private static final String s_name = "createaccountresponse";
4949

5050
@Inject
@@ -77,28 +77,33 @@ public class LdapCreateAccount extends BaseCmd {
7777
@Parameter(name = ApiConstants.USER_ID, type = CommandType.STRING, description = "User UUID, required for adding account from external provisioning system")
7878
private String userUUID;
7979

80-
public LdapCreateAccount() {
80+
public LdapCreateAccountCmd() {
8181
super();
8282
}
8383

84-
public LdapCreateAccount(final LdapManager ldapManager,
84+
public LdapCreateAccountCmd(final LdapManager ldapManager,
8585
final AccountService accountService) {
8686
super();
8787
_ldapManager = ldapManager;
8888
_accountService = accountService;
8989
}
9090

91+
UserAccount createCloudstackUserAccount(final LdapUser user) {
92+
return _accountService.createUserAccount(username, generatePassword(),
93+
user.getFirstname(), user.getLastname(), user.getEmail(),
94+
timezone, accountName, accountType, domainId, networkDomain,
95+
details, accountUUID, userUUID);
96+
}
97+
9198
@Override
9299
public void execute() throws ServerApiException {
93-
updateCallContext();
100+
final CallContext callContext = getCurrentContext();
101+
callContext.setEventDetails("Account Name: " + accountName
102+
+ ", Domain Id:" + domainId);
94103
try {
95104
final LdapUser user = _ldapManager.getUser(username);
96105
validateUser(user);
97-
final UserAccount userAccount = _accountService.createUserAccount(
98-
username, generatePassword(), user.getFirstname(),
99-
user.getLastname(), user.getEmail(), timezone, accountName,
100-
accountType, domainId, networkDomain, details, accountUUID,
101-
userUUID);
106+
final UserAccount userAccount = createCloudstackUserAccount(user);
102107
if (userAccount != null) {
103108
final AccountResponse response = _responseGenerator
104109
.createUserAccountResponse(userAccount);
@@ -132,16 +137,15 @@ public String getCommandName() {
132137
return s_name;
133138
}
134139

140+
CallContext getCurrentContext() {
141+
return CallContext.current();
142+
}
143+
135144
@Override
136145
public long getEntityOwnerId() {
137146
return Account.ACCOUNT_ID_SYSTEM;
138147
}
139148

140-
private void updateCallContext() {
141-
CallContext.current().setEventDetails(
142-
"Account Name: " + accountName + ", Domain Id:" + domainId);
143-
}
144-
145149
private boolean validateUser(final LdapUser user) throws ServerApiException {
146150
if (user.getEmail() == null) {
147151
throw new ServerApiException(

plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListAllUsersCmd.java renamed to plugins/user-authenticators/ldap/src/org/apache/cloudstack/api/command/LdapListUsersCmd.java

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,42 +23,56 @@
2323

2424
import org.apache.cloudstack.api.APICommand;
2525
import org.apache.cloudstack.api.BaseListCmd;
26+
import org.apache.cloudstack.api.Parameter;
2627
import org.apache.cloudstack.api.ServerApiException;
28+
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
2729
import org.apache.cloudstack.api.response.LdapUserResponse;
2830
import org.apache.cloudstack.api.response.ListResponse;
31+
import org.apache.cloudstack.api.response.UserResponse;
2932
import org.apache.cloudstack.ldap.LdapManager;
3033
import org.apache.cloudstack.ldap.LdapUser;
3134
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
35+
import org.apache.cloudstack.query.QueryService;
3236
import org.apache.log4j.Logger;
3337

3438
import com.cloud.user.Account;
3539

36-
@APICommand(name = "listAllLdapUsers", responseObject = LdapUserResponse.class, description = "Lists all LDAP Users", since = "4.2.0")
37-
public class LdapListAllUsersCmd extends BaseListCmd {
40+
@APICommand(name = "listLdapUsers", responseObject = LdapUserResponse.class, description = "Lists all LDAP Users", since = "4.2.0")
41+
public class LdapListUsersCmd extends BaseListCmd {
3842

3943
public static final Logger s_logger = Logger
40-
.getLogger(LdapListAllUsersCmd.class.getName());
44+
.getLogger(LdapListUsersCmd.class.getName());
4145
private static final String s_name = "ldapuserresponse";
4246
@Inject
4347
private LdapManager _ldapManager;
4448

45-
public LdapListAllUsersCmd() {
49+
@Inject
50+
private QueryService _queryService;
51+
52+
@Parameter(name = "listtype", type = CommandType.STRING, required = false, description = "Determines whether all ldap users are returned or just non-cloudstack users")
53+
private String listType;
54+
55+
public LdapListUsersCmd() {
4656
super();
4757
}
4858

49-
public LdapListAllUsersCmd(final LdapManager ldapManager) {
59+
public LdapListUsersCmd(final LdapManager ldapManager,
60+
final QueryService queryService) {
5061
super();
5162
_ldapManager = ldapManager;
63+
_queryService = queryService;
5264
}
5365

5466
private List<LdapUserResponse> createLdapUserResponse(
5567
final List<LdapUser> users) {
5668
final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
5769
for (final LdapUser user : users) {
58-
final LdapUserResponse ldapResponse = _ldapManager
59-
.createLdapUserResponse(user);
60-
ldapResponse.setObjectName("LdapUser");
61-
ldapResponses.add(ldapResponse);
70+
if (getListType().equals("all") || !isACloudstackUser(user)) {
71+
final LdapUserResponse ldapResponse = _ldapManager
72+
.createLdapUserResponse(user);
73+
ldapResponse.setObjectName("LdapUser");
74+
ldapResponses.add(ldapResponse);
75+
}
6276
}
6377
return ldapResponses;
6478
}
@@ -88,4 +102,22 @@ public String getCommandName() {
88102
public long getEntityOwnerId() {
89103
return Account.ACCOUNT_ID_SYSTEM;
90104
}
105+
106+
private String getListType() {
107+
return listType == null ? "all" : listType;
108+
}
109+
110+
private boolean isACloudstackUser(final LdapUser ldapUser) {
111+
final ListResponse<UserResponse> response = _queryService
112+
.searchForUsers(new ListUsersCmd());
113+
final List<UserResponse> cloudstackUsers = response.getResponses();
114+
if (cloudstackUsers != null && cloudstackUsers.size() != 0) {
115+
for (final UserResponse cloudstackUser : response.getResponses()) {
116+
if (ldapUser.getUsername().equals(cloudstackUser.getUsername())) {
117+
return true;
118+
}
119+
}
120+
}
121+
return false;
122+
}
91123
}

plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapManagerImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@
2626

2727
import org.apache.cloudstack.api.LdapValidator;
2828
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd;
29-
import org.apache.cloudstack.api.command.LdapCreateAccount;
29+
import org.apache.cloudstack.api.command.LdapCreateAccountCmd;
3030
import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd;
31-
import org.apache.cloudstack.api.command.LdapListAllUsersCmd;
3231
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
32+
import org.apache.cloudstack.api.command.LdapListUsersCmd;
3333
import org.apache.cloudstack.api.command.LdapUserSearchCmd;
3434
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
3535
import org.apache.cloudstack.api.response.LdapUserResponse;
@@ -159,11 +159,11 @@ public LdapConfigurationResponse deleteConfiguration(final String hostname)
159159
public List<Class<?>> getCommands() {
160160
final List<Class<?>> cmdList = new ArrayList<Class<?>>();
161161
cmdList.add(LdapUserSearchCmd.class);
162-
cmdList.add(LdapListAllUsersCmd.class);
162+
cmdList.add(LdapListUsersCmd.class);
163163
cmdList.add(LdapAddConfigurationCmd.class);
164164
cmdList.add(LdapDeleteConfigurationCmd.class);
165165
cmdList.add(LdapListConfigurationCmd.class);
166-
cmdList.add(LdapCreateAccount.class);
166+
cmdList.add(LdapCreateAccountCmd.class);
167167
return cmdList;
168168
}
169169

plugins/user-authenticators/ldap/test/groovy/org/apache/cloudstack/ldap/BasicNamingEnumerationImpl.groovy

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,41 @@
1616
// under the License.
1717
package groovy.org.apache.cloudstack.ldap
1818

19-
import java.util.LinkedList;
20-
21-
import javax.naming.NamingEnumeration;
22-
import javax.naming.NamingException;
23-
import javax.naming.directory.SearchResult;
19+
import javax.naming.NamingEnumeration
20+
import javax.naming.NamingException
21+
import javax.naming.directory.SearchResult
2422

2523
class BasicNamingEnumerationImpl implements NamingEnumeration {
2624

27-
private LinkedList<String> items = new LinkedList<SearchResult>();
28-
29-
public void add(SearchResult item) {
30-
items.add(item)
31-
}
32-
33-
@Override
34-
public void close() throws NamingException {
35-
}
36-
37-
@Override
38-
public boolean hasMore() throws NamingException {
39-
return hasMoreElements();
40-
}
41-
42-
@Override
43-
public boolean hasMoreElements() {
44-
return items.size != 0;
45-
}
46-
47-
@Override
48-
public Object next() throws NamingException {
49-
return nextElement();
50-
}
51-
52-
@Override
53-
public Object nextElement() {
54-
SearchResult result = items.getFirst();
55-
items.removeFirst();
56-
return result;
57-
}
25+
private LinkedList<String> items = new LinkedList<SearchResult>();
26+
27+
public void add(SearchResult item) {
28+
items.add(item)
29+
}
30+
31+
@Override
32+
public void close() throws NamingException {
33+
}
34+
35+
@Override
36+
public boolean hasMore() throws NamingException {
37+
return hasMoreElements();
38+
}
39+
40+
@Override
41+
public boolean hasMoreElements() {
42+
return items.size != 0;
43+
}
44+
45+
@Override
46+
public Object next() throws NamingException {
47+
return nextElement();
48+
}
49+
50+
@Override
51+
public Object nextElement() {
52+
SearchResult result = items.getFirst();
53+
items.removeFirst();
54+
return result;
55+
}
5856
}

0 commit comments

Comments
 (0)