Cloudstack-2014 [GSoC] Add support for ldap user provisioning

This commit is contained in:
Ian Duffy 2013-08-31 22:01:04 +01:00
commit f80ecfe4b0
80 changed files with 5298 additions and 1460 deletions

3
.gitignore vendored
View File

@ -81,4 +81,5 @@ debian/*.debhelper
replace.properties.tmp
build-indep-stamp
configure-stamp
*_flymake.js
*_flymake.js
engine/storage/integration-test/test-output

View File

@ -21,8 +21,6 @@ import java.util.List;
import javax.naming.NamingException;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
@ -261,12 +259,6 @@ public interface ConfigurationService {
Long getDefaultPageSize();
boolean updateLDAP(LDAPConfigCmd cmd) throws NamingException;
boolean removeLDAP(LDAPRemoveCmd cmd);
LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd);
PortableIpRange createPortableIpRange(CreatePortableIpRangeCmd cmd) throws ConcurrentOperationException;
boolean deletePortableIpRange(DeletePortableIpRangeCmd cmd);

View File

@ -525,15 +525,4 @@ public class ApiConstants {
public enum VMDetails {
all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min, affgrp;
}
public enum LDAPParams {
hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass;
@Override
public String toString() {
return "ldap." + name();
}
}
}

View File

@ -0,0 +1,5 @@
package org.apache.cloudstack.api;
public interface LdapValidator {
boolean isLdapEnabled();
}

View File

@ -60,7 +60,6 @@ import org.apache.cloudstack.api.response.IpForwardingRuleResponse;
import org.apache.cloudstack.api.response.IsolationMethodResponse;
import org.apache.cloudstack.api.response.LBHealthCheckResponse;
import org.apache.cloudstack.api.response.LBStickinessResponse;
import org.apache.cloudstack.api.response.LDAPConfigResponse;
import org.apache.cloudstack.api.response.LoadBalancerResponse;
import org.apache.cloudstack.api.response.NetworkACLItemResponse;
import org.apache.cloudstack.api.response.NetworkACLResponse;
@ -354,8 +353,6 @@ public interface ResponseGenerator {
VirtualRouterProviderResponse createVirtualRouterProviderResponse(VirtualRouterProvider result);
LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String baseSearch, String dn);
StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result);
RegionResponse createRegionResponse(Region region);

View File

@ -1,205 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command.admin.ldap;
import java.util.ArrayList;
import java.util.List;
import javax.naming.NamingException;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.LDAPConfigResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.log4j.Logger;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "ldapConfig", description="Configure the LDAP context for this site.", responseObject=LDAPConfigResponse.class, since="3.0.0")
public class LDAPConfigCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(LDAPConfigCmd.class.getName());
private static final String s_name = "ldapconfigresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name=ApiConstants.LIST_ALL, type=CommandType.BOOLEAN, description="If true return current LDAP configuration")
private Boolean listAll;
@Parameter(name=ApiConstants.HOST_NAME, type=CommandType.STRING, description="Hostname or ip address of the ldap server eg: my.ldap.com")
private String hostname;
@Parameter(name=ApiConstants.PORT, type=CommandType.INTEGER, description="Specify the LDAP port if required, default is 389.")
private Integer port=0;
@Parameter(name=ApiConstants.USE_SSL, type=CommandType.BOOLEAN, description="Check Use SSL if the external LDAP server is configured for LDAP over SSL.")
private Boolean useSSL;
@Parameter(name=ApiConstants.SEARCH_BASE, type=CommandType.STRING, description="The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.")
private String searchBase;
@Parameter(name=ApiConstants.QUERY_FILTER, type=CommandType.STRING, description="You specify a query filter here, which narrows down the users, who can be part of this domain.")
private String queryFilter;
@Parameter(name=ApiConstants.BIND_DN, type=CommandType.STRING, description="Specify the distinguished name of a user with the search permission on the directory.")
private String bindDN;
@Parameter(name=ApiConstants.BIND_PASSWORD, type=CommandType.STRING, description="Enter the password.")
private String bindPassword;
@Parameter(name=ApiConstants.TRUST_STORE, type=CommandType.STRING, description="Enter the path to trust certificates store.")
private String trustStore;
@Parameter(name=ApiConstants.TRUST_STORE_PASSWORD, type=CommandType.STRING, description="Enter the password for trust store.")
private String trustStorePassword;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Boolean getListAll() {
return listAll == null ? Boolean.FALSE : listAll;
}
public String getBindPassword() {
return bindPassword;
}
public String getBindDN() {
return bindDN;
}
public void setBindDN(String bdn) {
this.bindDN=bdn;
}
public String getQueryFilter() {
return queryFilter;
}
public void setQueryFilter(String queryFilter) {
this.queryFilter=queryFilter;
}
public String getSearchBase() {
return searchBase;
}
public void setSearchBase(String searchBase) {
this.searchBase=searchBase;
}
public Boolean getUseSSL() {
return useSSL == null ? Boolean.FALSE : useSSL;
}
public void setUseSSL(Boolean useSSL) {
this.useSSL=useSSL;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname=hostname;
}
public Integer getPort() {
return port <= 0 ? 389 : port;
}
public void setPort(Integer port) {
this.port=port;
}
public String getTrustStore() {
return trustStore;
}
public void setTrustStore(String trustStore) {
this.trustStore=trustStore;
}
public String getTrustStorePassword() {
return trustStorePassword;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException,
InsufficientCapacityException, ServerApiException,
ConcurrentOperationException, ResourceAllocationException {
try {
if (getListAll()){
// return the existing conf
LDAPConfigCmd cmd = _configService.listLDAPConfig(this);
ListResponse<LDAPConfigResponse> response = new ListResponse<LDAPConfigResponse>();
List<LDAPConfigResponse> responses = new ArrayList<LDAPConfigResponse>();
if(!cmd.getHostname().equals("")) {
responses.add(_responseGenerator.createLDAPConfigResponse(cmd.getHostname(), cmd.getPort(), cmd.getUseSSL(), cmd.getQueryFilter(), cmd.getSearchBase(), cmd.getBindDN()));
}
response.setResponses(responses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
else if (getHostname()==null || getSearchBase() == null || getQueryFilter() == null) {
throw new InvalidParameterValueException("You need to provide hostname, searchbase and queryfilter to configure your LDAP server");
}
else {
boolean result = _configService.updateLDAP(this);
if (result){
LDAPConfigResponse lr = _responseGenerator.createLDAPConfigResponse(getHostname(), getPort(), getUseSSL(), getQueryFilter(), getSearchBase(), getBindDN());
lr.setResponseName(getCommandName());
this.setResponseObject(lr);
}
}
}
catch (NamingException ne){
ne.printStackTrace();
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -1,71 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command.admin.ldap;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.response.LDAPConfigResponse;
import org.apache.cloudstack.api.response.LDAPRemoveResponse;
import org.apache.log4j.Logger;
import com.cloud.user.Account;
@APICommand(name = "ldapRemove", description="Remove the LDAP context for this site.", responseObject=LDAPConfigResponse.class, since="3.0.1")
public class LDAPRemoveCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(LDAPRemoveCmd.class.getName());
private static final String s_name = "ldapremoveresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute(){
boolean result = _configService.removeLDAP(this);
if (result){
LDAPRemoveResponse lr = new LDAPRemoveResponse();
lr.setObjectName("ldapremove");
lr.setResponseName(getCommandName());
this.setResponseObject(lr);
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -1,105 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class LDAPConfigResponse extends BaseResponse {
@SerializedName(ApiConstants.HOST_NAME) @Param(description="Hostname or ip address of the ldap server eg: my.ldap.com")
private String hostname;
@SerializedName(ApiConstants.PORT) @Param(description="Specify the LDAP port if required, default is 389")
private String port;
@SerializedName(ApiConstants.USE_SSL) @Param(description="Check Use SSL if the external LDAP server is configured for LDAP over SSL")
private String useSSL;
@SerializedName(ApiConstants.SEARCH_BASE) @Param(description="The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com")
private String searchBase;
@SerializedName(ApiConstants.QUERY_FILTER) @Param(description="You specify a query filter here, which narrows down the users, who can be part of this domain")
private String queryFilter;
@SerializedName(ApiConstants.BIND_DN) @Param(description="Specify the distinguished name of a user with the search permission on the directory")
private String bindDN;
@SerializedName(ApiConstants.BIND_PASSWORD) @Param(description="DN password")
private String bindPassword;
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public String getUseSSL() {
return useSSL;
}
public void setUseSSL(String useSSL) {
this.useSSL = useSSL;
}
public String getSearchBase() {
return searchBase;
}
public void setSearchBase(String searchBase) {
this.searchBase = searchBase;
}
public String getQueryFilter() {
return queryFilter;
}
public void setQueryFilter(String queryFilter) {
this.queryFilter = queryFilter;
}
public String getBindDN() {
return bindDN;
}
public void setBindDN(String bindDN) {
this.bindDN = bindDN;
}
public String getBindPassword() {
return bindPassword;
}
public void setBindPassword(String bindPassword) {
this.bindPassword = bindPassword;
}
}

View File

@ -43,6 +43,7 @@ message.action.delete.nic=Please confirm that want to remove this NIC, which wil
changed.item.properties=Changed item properties
confirm.enable.s3=Please fill in the following information to enable support for S3-backed Secondary Storage
confirm.enable.swift=Please fill in the following information to enable support for Swift
error.could.not.change.your.password.because.ldap.is.enabled=Error cloud not change your password because LDAP is enabled.
error.could.not.enable.zone=Could not enable zone
error.installWizard.message=Something went wrong; you may go back and correct any errors
error.invalid.username.password=Invalid username or password

View File

@ -387,7 +387,7 @@
<bean id="MD5UserAuthenticator" class="com.cloud.server.auth.MD5UserAuthenticator">
<property name="name" value="MD5"/>
</bean>
<bean id="LDAPUserAuthenticator" class="com.cloud.server.auth.LDAPUserAuthenticator">
<bean id="LdapAuthenticator" class="org.apache.cloudstack.ldap.LdapAuthenticator">
<property name="name" value="LDAP"/>
</bean>
<bean id="SHA256SaltedUserAuthenticator" class="com.cloud.server.auth.SHA256SaltedUserAuthenticator">
@ -396,6 +396,11 @@
<bean id="PlainTextUserAuthenticator" class="com.cloud.server.auth.PlainTextUserAuthenticator">
<property name="name" value="PLAINTEXT"/>
</bean>
<bean id="LdapManager" class="org.apache.cloudstack.ldap.LdapManagerImpl" />
<bean id="LdapUserManager" class="org.apache.cloudstack.ldap.LdapUserManager" />
<bean id="LdapContextFactory" class="org.apache.cloudstack.ldap.LdapContextFactory" />
<bean id="LdapConfigurationDao" class="org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl" />
<bean id="LdapConfiguration" class="org.apache.cloudstack.ldap.LdapConfiguration" />
<!--
Network Elements

View File

@ -5,9 +5,9 @@
# to you 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
@ -210,8 +210,6 @@ scaleSystemVm=1
#### configuration commands
updateConfiguration=1
listConfigurations=1
ldapConfig=1
ldapRemove=1
listCapabilities=15
listDeploymentPlanners=1
cleanVMReservations=1
@ -386,12 +384,12 @@ listProjectInvitations=15
updateProjectInvitation=15
deleteProjectInvitation=15
####
####
createFirewallRule=15
deleteFirewallRule=15
listFirewallRules=15
####
####
createEgressFirewallRule=15
deleteEgressFirewallRule=15
listEgressFirewallRules=15
@ -673,3 +671,10 @@ listDedicatedZones=1
listDedicatedPods=1
listDedicatedClusters=1
listDedicatedHosts=1
### LDAP
listLdapConfigurations=15
addLdapConfiguration=3
deleteLdapConfiguration=3
listLdapUsers=3
ldapCreateAccount=3

View File

@ -127,7 +127,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>
@ -137,7 +137,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>

View File

@ -224,7 +224,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>
@ -234,7 +234,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>

View File

@ -73,7 +73,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>
@ -83,7 +83,7 @@
<list>
<ref bean="SHA256SaltedUserAuthenticator"/>
<ref bean="MD5UserAuthenticator"/>
<ref bean="LDAPUserAuthenticator"/>
<ref bean="LdapAuthenticator"/>
<ref bean="PlainTextUserAuthenticator"/>
</list>
</property>

View File

@ -24,19 +24,28 @@
<section id="LDAP-for-user-authentication">
<title>Using an LDAP Server for User Authentication</title>
<para>You can use an external LDAP server such as Microsoft Active Directory or OpenLDAP to authenticate &PRODUCT; end-users.</para>
<para>To set up LDAP authentication in &PRODUCT;, open the global settings page and set:</para>
<para>In order to do this you must:</para>
<itemizedlist>
<listitem><para>ldap.basedn - The base directory you want to search within for uses</para></listitem>
<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>
<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>
<listitem><para>ldap.email.attribute - The attribute within your LDAP server that holds a value for users email address</para></listitem>
<listitem><para>ldap.realname.attribute - The attribute within your LDAP server that holds a value users realname</para></listitem>
<listitem><para>ldap.user.object - The object class that identifies a user</para></listitem>
<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>
<listitem><para>Set your LDAP configuration within &PRODUCT;</para></listitem>
<listitem><para>Create &PRODUCT; accounts for LDAP users</para></listitem>
</itemizedlist>
<para>Finally you can add LDAP servers from Global Settings -> Select View -> LDAP Configuration. This requires a hostname and port</para>
<para>To set up LDAP authentication in &PRODUCT;, open the global settings page and search for LDAP</para>
<para>Set ldap.basedn to match your sever's base directory.</para>
<para>Review the defaults for the following, ensure that they match your schema.</para>
<itemizedlist>
<listitem><para>ldap.email.attribute</para></listitem>
<listitem><para>ldap.firstname.attribute</para></listitem>
<listitem><para>ldap.lastname.attribute</para></listitem>
<listitem><para>ldap.username.attribute</para></listitem>
<listitem><para>ldap.user.object</para></listitem>
</itemizedlist>
<para>Optionally you can set the following:</para>
<itemizedlist>
<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>
<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>
<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>
</itemizedlist>
<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>
<xi:include href="example-activedirectory-configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="example-openldap-configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<!-- Support for SSL has been removed but will be back shortly. -->
<!-- <xi:include href="SSL-keystore-path-and-password.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> -->
</section>

View File

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

View File

@ -24,8 +24,8 @@
<section id="example-openldap-configuration">
<title>Example LDAP Configuration for OpenLdap</title>
<para>This shows the configuration settings required for using OpenLDAP</para>
<para>The default values supplied are suited for OpenLDAP</para>
<para>This shows the configuration settings required for using OpenLDAP.</para>
<para>The default values supplied are suited for OpenLDAP.</para>
<itemizedlist>
<listitem><para>uid - Logon name</para></listitem>
<listitem><para>mail - Email Address</para></listitem>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -30,7 +30,6 @@ import net.sf.ehcache.CacheManager;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
import org.apache.cloudstack.api.command.admin.ratelimit.ResetApiLimitCmd;
import org.apache.cloudstack.api.command.user.ratelimit.GetApiLimitCmd;
import org.apache.cloudstack.api.response.ApiLimitResponse;

View File

@ -1,22 +1,14 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to you 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. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-user-authenticator-ldap</artifactId>
<name>Apache CloudStack Plugin - User Authenticator LDAP</name>
@ -26,4 +18,93 @@
<version>4.3.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<configuration>
<providerSelection>1.7</providerSelection>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<sources>
<fileset>
<directory>test/groovy</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</fileset>
</sources>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-1.7</artifactId>
<version>1.3</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.0.5</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Spec*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>com.btmatthews.maven.plugins</groupId>
<artifactId>ldap-maven-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<monitorPort>11389</monitorPort>
<monitorKey>ldap</monitorKey>
<daemon>false</daemon>
<rootDn>dc=cloudstack,dc=org</rootDn>
<ldapPort>10389</ldapPort>
<ldifFile>test/resources/cloudstack.org.ldif</ldifFile>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Mandatory dependencies for using Spock -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>0.7-groovy-2.0</version>
</dependency>
<!-- Optional dependencies for using Spock -->
<dependency> <!-- enables mocking of classes (in addition to interfaces) -->
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
</project>

View File

@ -1,174 +0,0 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 com.cloud.server.auth;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Hashtable;
import java.util.Map;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
import com.cloud.utils.exception.CloudRuntimeException;
@Local(value={UserAuthenticator.class})
public class LDAPUserAuthenticator extends DefaultUserAuthenticator {
public static final Logger s_logger = Logger.getLogger(LDAPUserAuthenticator.class);
@Inject private ConfigurationDao _configDao;
@Inject private UserAccountDao _userAccountDao;
@Override
public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters ) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Retrieving user: " + username);
}
UserAccount user = _userAccountDao.getUserAccount(username, domainId);
if (user == null) {
s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
return false;
}
String url = _configDao.getValue(LDAPParams.hostname.toString());
if (url==null){
s_logger.debug("LDAP authenticator is not configured.");
return false;
}
String port = _configDao.getValue(LDAPParams.port.toString());
String queryFilter = _configDao.getValue(LDAPParams.queryfilter.toString());
String searchBase = _configDao.getValue(LDAPParams.searchbase.toString());
Boolean useSSL = Boolean.valueOf(_configDao.getValue(LDAPParams.usessl.toString()));
String bindDN = _configDao.getValue(LDAPParams.dn.toString());
String bindPasswd = _configDao.getValue(LDAPParams.passwd.toString());
String trustStore = _configDao.getValue(LDAPParams.truststore.toString());
String trustStorePassword = _configDao.getValue(LDAPParams.truststorepass.toString());
try {
// get all params
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
String protocol = "ldap://" ;
if (useSSL){
env.put(Context.SECURITY_PROTOCOL, "ssl");
protocol="ldaps://" ;
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
}
env.put(Context.PROVIDER_URL, protocol + url + ":" + port);
if (bindDN != null && bindPasswd != null){
env.put(Context.SECURITY_PRINCIPAL, bindDN);
env.put(Context.SECURITY_CREDENTIALS, bindPasswd);
}
else {
// Use anonymous authentication
env.put(Context.SECURITY_AUTHENTICATION, "none");
}
// Create the initial context
DirContext ctx = new InitialDirContext(env);
// use this context to search
// substitute the queryFilter with this user info
queryFilter = queryFilter.replaceAll("\\%u", username);
queryFilter = queryFilter.replaceAll("\\%n", user.getFirstname() + " " + user.getLastname());
queryFilter = queryFilter.replaceAll("\\%e", user.getEmail());
SearchControls sc = new SearchControls();
String[] searchFilter = { "dn" };
sc.setReturningAttributes(new String[0]); //return no attributes
sc.setReturningAttributes(searchFilter);
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
sc.setCountLimit(1);
// Search for objects with those matching attributes
NamingEnumeration<SearchResult> answer = ctx.search(searchBase, queryFilter, sc);
SearchResult sr = answer.next();
String cn = sr.getName();
answer.close();
ctx.close();
s_logger.info("DN from LDAP =" + cn);
// check the password
env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
protocol = "ldap://" ;
if (useSSL){
env.put(Context.SECURITY_PROTOCOL, "ssl");
protocol="ldaps://" ;
}
env.put(Context.PROVIDER_URL, protocol + url + ":" + port);
env.put(Context.SECURITY_PRINCIPAL, cn + "," + searchBase);
env.put(Context.SECURITY_CREDENTIALS, password);
// Create the initial context
ctx = new InitialDirContext(env);
ctx.close();
} catch (NamingException ne) {
s_logger.warn("Authentication Failed ! " + ne.getMessage() + (ne.getCause() != null ? ("; Caused by:" + ne.getCause().getMessage()) : ""));
return false;
}
catch (Exception e){
e.printStackTrace();
s_logger.warn("Unknown error encountered " + e.getMessage());
return false;
}
// authenticate
return true;
}
@Override
public boolean configure(String name, Map<String, Object> params)
throws ConfigurationException {
if (name == null) {
name = "LDAP";
}
super.configure(name, params);
return true;
}
@Override
public String encode(String password) {
// Password is not used, so set to a random string
try {
SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
byte bytes[] = new byte[20];
randomGen.nextBytes(bytes);
return Base64.encode(bytes).toString();
} catch (NoSuchAlgorithmException e) {
throw new CloudRuntimeException("Failed to generate random password",e);
}
}
}

View File

@ -0,0 +1,82 @@
package org.apache.cloudstack.api.command;
import javax.inject.Inject;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "addLdapConfiguration", description = "Add a new Ldap Configuration", responseObject = LdapConfigurationResponse.class, since = "4.2.0")
public class LdapAddConfigurationCmd extends BaseCmd {
public static final Logger s_logger = Logger
.getLogger(LdapAddConfigurationCmd.class.getName());
private static final String s_name = "ldapconfigurationresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
private String hostname;
@Parameter(name = "port", type = CommandType.INTEGER, required = true, description = "Port")
private int port;
public LdapAddConfigurationCmd() {
super();
}
public LdapAddConfigurationCmd(final LdapManager ldapManager) {
super();
_ldapManager = ldapManager;
}
@Override
public void execute() throws ServerApiException {
try {
final LdapConfigurationResponse response = _ldapManager
.addConfiguration(hostname, port);
response.setObjectName("LdapAddConfiguration");
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (final InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
e.toString());
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
public void setPort(final int port) {
this.port = port;
}
}

View File

@ -0,0 +1,167 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
import javax.inject.Inject;
import javax.naming.NamingException;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.UserAccount;
@APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0")
public class LdapCreateAccountCmd extends BaseCmd {
public static final Logger s_logger = Logger
.getLogger(LdapCreateAccountCmd.class.getName());
private static final String s_name = "createaccountresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.")
private String accountName;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin")
private Short accountType;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.")
private Long domainId;
@Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
private String timezone;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Unique username.")
private String username;
@Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, description = "Network domain for the account's networks")
private String networkDomain;
@Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters")
private Map<String, String> details;
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.STRING, description = "Account UUID, required for adding account from external provisioning system")
private String accountUUID;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.STRING, description = "User UUID, required for adding account from external provisioning system")
private String userUUID;
public LdapCreateAccountCmd() {
super();
}
public LdapCreateAccountCmd(final LdapManager ldapManager,
final AccountService accountService) {
super();
_ldapManager = ldapManager;
_accountService = accountService;
}
UserAccount createCloudstackUserAccount(final LdapUser user) {
return _accountService.createUserAccount(username, generatePassword(),
user.getFirstname(), user.getLastname(), user.getEmail(),
timezone, accountName, accountType, domainId, networkDomain,
details, accountUUID, userUUID);
}
@Override
public void execute() throws ServerApiException {
final CallContext callContext = getCurrentContext();
callContext.setEventDetails("Account Name: " + accountName
+ ", Domain Id:" + domainId);
try {
final LdapUser user = _ldapManager.getUser(username);
validateUser(user);
final UserAccount userAccount = createCloudstackUserAccount(user);
if (userAccount != null) {
final AccountResponse response = _responseGenerator
.createUserAccountResponse(userAccount);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to create a user account");
}
} catch (final NamingException e) {
throw new ServerApiException(
ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR,
"No LDAP user exists with the username of " + username);
}
}
private String generatePassword() throws ServerApiException {
try {
final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
final byte bytes[] = new byte[20];
randomGen.nextBytes(bytes);
return Base64.encode(bytes).toString();
} catch (final NoSuchAlgorithmException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
"Failed to generate random password");
}
}
@Override
public String getCommandName() {
return s_name;
}
CallContext getCurrentContext() {
return CallContext.current();
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
private boolean validateUser(final LdapUser user) throws ServerApiException {
if (user.getEmail() == null) {
throw new ServerApiException(
ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username
+ " has no email address set within LDAP");
}
if (user.getFirstname() == null) {
throw new ServerApiException(
ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username
+ " has no firstname set within LDAP");
}
if (user.getLastname() == null) {
throw new ServerApiException(
ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username
+ " has no lastname set within LDAP");
}
return true;
}
}

View File

@ -0,0 +1,78 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command;
import javax.inject.Inject;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.log4j.Logger;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "deleteLdapConfiguration", description = "Remove an Ldap Configuration", responseObject = LdapConfigurationResponse.class, since = "4.2.0")
public class LdapDeleteConfigurationCmd extends BaseCmd {
public static final Logger s_logger = Logger
.getLogger(LdapDeleteConfigurationCmd.class.getName());
private static final String s_name = "ldapconfigurationresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = true, description = "Hostname")
private String hostname;
public LdapDeleteConfigurationCmd() {
super();
}
public LdapDeleteConfigurationCmd(final LdapManager ldapManager) {
super();
_ldapManager = ldapManager;
}
@Override
public void execute() throws ServerApiException {
try {
final LdapConfigurationResponse response = _ldapManager
.deleteConfiguration(hostname);
response.setObjectName("LdapDeleteConfiguration");
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (final InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR,
e.toString());
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,110 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.ldap.LdapConfigurationVO;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.log4j.Logger;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
@APICommand(name = "listLdapConfigurations", responseObject = LdapConfigurationResponse.class, description = "Lists all LDAP configurations", since = "4.2.0")
public class LdapListConfigurationCmd extends BaseListCmd {
public static final Logger s_logger = Logger
.getLogger(LdapListConfigurationCmd.class.getName());
private static final String s_name = "ldapconfigurationresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = "hostname", type = CommandType.STRING, required = false, description = "Hostname")
private String hostname;
@Parameter(name = "port", type = CommandType.INTEGER, required = false, description = "Port")
private int port;
public LdapListConfigurationCmd() {
super();
}
public LdapListConfigurationCmd(final LdapManager ldapManager) {
super();
_ldapManager = ldapManager;
}
private List<LdapConfigurationResponse> createLdapConfigurationResponses(
final List<? extends LdapConfigurationVO> configurations) {
final List<LdapConfigurationResponse> responses = new ArrayList<LdapConfigurationResponse>();
for (final LdapConfigurationVO resource : configurations) {
final LdapConfigurationResponse configurationResponse = _ldapManager
.createLdapConfigurationResponse(resource);
configurationResponse.setObjectName("LdapConfiguration");
responses.add(configurationResponse);
}
return responses;
}
@Override
public void execute() {
final Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager
.listConfigurations(this);
final List<LdapConfigurationResponse> responses = createLdapConfigurationResponses(result
.first());
final ListResponse<LdapConfigurationResponse> response = new ListResponse<LdapConfigurationResponse>();
response.setResponses(responses, result.second());
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
public void setPort(final int port) {
this.port = port;
}
}

View File

@ -0,0 +1,123 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import org.apache.cloudstack.query.QueryService;
import org.apache.log4j.Logger;
import com.cloud.user.Account;
@APICommand(name = "listLdapUsers", responseObject = LdapUserResponse.class, description = "Lists all LDAP Users", since = "4.2.0")
public class LdapListUsersCmd extends BaseListCmd {
public static final Logger s_logger = Logger
.getLogger(LdapListUsersCmd.class.getName());
private static final String s_name = "ldapuserresponse";
@Inject
private LdapManager _ldapManager;
@Inject
private QueryService _queryService;
@Parameter(name = "listtype", type = CommandType.STRING, required = false, description = "Determines whether all ldap users are returned or just non-cloudstack users")
private String listType;
public LdapListUsersCmd() {
super();
}
public LdapListUsersCmd(final LdapManager ldapManager,
final QueryService queryService) {
super();
_ldapManager = ldapManager;
_queryService = queryService;
}
private List<LdapUserResponse> createLdapUserResponse(
final List<LdapUser> users) {
final List<LdapUserResponse> ldapResponses = new ArrayList<LdapUserResponse>();
for (final LdapUser user : users) {
if (getListType().equals("all") || !isACloudstackUser(user)) {
final LdapUserResponse ldapResponse = _ldapManager
.createLdapUserResponse(user);
ldapResponse.setObjectName("LdapUser");
ldapResponses.add(ldapResponse);
}
}
return ldapResponses;
}
@Override
public void execute() throws ServerApiException {
List<LdapUserResponse> ldapResponses = null;
final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
try {
final List<LdapUser> users = _ldapManager.getUsers();
ldapResponses = createLdapUserResponse(users);
} catch (final NoLdapUserMatchingQueryException ex) {
ldapResponses = new ArrayList<LdapUserResponse>();
} finally {
response.setResponses(ldapResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
private String getListType() {
return listType == null ? "all" : listType;
}
private boolean isACloudstackUser(final LdapUser ldapUser) {
final ListResponse<UserResponse> response = _queryService
.searchForUsers(new ListUsersCmd());
final List<UserResponse> cloudstackUsers = response.getResponses();
if (cloudstackUsers != null && cloudstackUsers.size() != 0) {
for (final UserResponse cloudstackUser : response.getResponses()) {
if (ldapUser.getUsername().equals(cloudstackUser.getUsername())) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,98 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.command;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import org.apache.log4j.Logger;
import com.cloud.user.Account;
@APICommand(name = "searchLdap", responseObject = LdapUserResponse.class, description = "Searches LDAP based on the username attribute", since = "4.2.0")
public class LdapUserSearchCmd extends BaseListCmd {
public static final Logger s_logger = Logger
.getLogger(LdapUserSearchCmd.class.getName());
private static final String s_name = "ldapuserresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = "query", type = CommandType.STRING, entityType = LdapUserResponse.class, required = true, description = "query to search using")
private String query;
public LdapUserSearchCmd() {
super();
}
public LdapUserSearchCmd(final LdapManager ldapManager) {
super();
_ldapManager = ldapManager;
}
private List<LdapUserResponse> createLdapUserResponse(
final List<LdapUser> users) {
final List<LdapUserResponse> ldapUserResponses = new ArrayList<LdapUserResponse>();
if (users != null) {
for (final LdapUser user : users) {
final LdapUserResponse ldapUserResponse = _ldapManager
.createLdapUserResponse(user);
ldapUserResponse.setObjectName("LdapUser");
ldapUserResponses.add(ldapUserResponse);
}
}
return ldapUserResponses;
}
@Override
public void execute() {
final ListResponse<LdapUserResponse> response = new ListResponse<LdapUserResponse>();
List<LdapUser> users = null;
try {
users = _ldapManager.searchUsers(query);
} catch (final NoLdapUserMatchingQueryException e) {
s_logger.debug(e.getMessage());
}
final List<LdapUserResponse> ldapUserResponses = createLdapUserResponse(users);
response.setResponses(ldapUserResponses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,62 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.response;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class LdapConfigurationResponse extends BaseResponse {
@SerializedName("hostname")
@Param(description = "hostname")
private String hostname;
@SerializedName("port")
@Param(description = "port")
private int port;
public LdapConfigurationResponse() {
super();
}
public LdapConfigurationResponse(final String hostname) {
super();
this.hostname = hostname;
}
public LdapConfigurationResponse(final String hostname, final int port) {
this.hostname = hostname;
this.port = port;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public void setHostname(final String hostname) {
this.hostname = hostname;
}
public void setPort(final int port) {
this.port = port;
}
}

View File

@ -0,0 +1,99 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.api.response;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class LdapUserResponse extends BaseResponse {
@SerializedName("email")
@Param(description = "The user's email")
private String email;
@SerializedName("principal")
@Param(description = "The user's principle")
private String principal;
@SerializedName("firstname")
@Param(description = "The user's firstname")
private String firstname;
@SerializedName("lastname")
@Param(description = "The user's lastname")
private String lastname;
@SerializedName("username")
@Param(description = "The user's username")
private String username;
public LdapUserResponse() {
super();
}
public LdapUserResponse(final String username, final String email,
final String firstname, final String lastname,
final String principal) {
super();
this.username = username;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.principal = principal;
}
public String getEmail() {
return email;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public String getPrincipal() {
return principal;
}
public String getUsername() {
return username;
}
public void setEmail(final String email) {
this.email = email;
}
public void setFirstname(final String firstname) {
this.firstname = firstname;
}
public void setLastname(final String lastname) {
this.lastname = lastname;
}
public void setPrincipal(final String principal) {
this.principal = principal;
}
public void setUsername(final String username) {
this.username = username;
}
}

View File

@ -0,0 +1,71 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.Map;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import com.cloud.server.auth.DefaultUserAuthenticator;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
public class LdapAuthenticator extends DefaultUserAuthenticator {
private static final Logger s_logger = Logger
.getLogger(LdapAuthenticator.class.getName());
@Inject
private LdapManager _ldapManager;
@Inject
private UserAccountDao _userAccountDao;
public LdapAuthenticator() {
super();
}
public LdapAuthenticator(final LdapManager ldapManager,
final UserAccountDao userAccountDao) {
super();
_ldapManager = ldapManager;
_userAccountDao = userAccountDao;
}
@Override
public boolean authenticate(final String username, final String password,
final Long domainId, final Map<String, Object[]> requestParameters) {
final UserAccount user = _userAccountDao.getUserAccount(username,
domainId);
if (user == null) {
s_logger.debug("Unable to find user with " + username
+ " in domain " + domainId);
return false;
} else if (_ldapManager.isLdapEnabled()) {
return _ldapManager.canAuthenticate(username, password);
} else {
return false;
}
}
@Override
public String encode(final String password) {
return password;
}
}

View File

@ -0,0 +1,145 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.List;
import javax.inject.Inject;
import javax.naming.directory.SearchControls;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.utils.Pair;
public class LdapConfiguration {
private final static String factory = "com.sun.jndi.ldap.LdapCtxFactory";
private final static int scope = SearchControls.SUBTREE_SCOPE;
@Inject
private ConfigurationDao _configDao;
@Inject
private LdapManager _ldapManager;
public LdapConfiguration() {
}
public LdapConfiguration(final ConfigurationDao configDao,
final LdapManager ldapManager) {
_configDao = configDao;
_ldapManager = ldapManager;
}
public String getAuthentication() {
if ((getBindPrincipal() == null) && (getBindPassword() == null)) {
return "none";
} else {
return "simple";
}
}
public String getBaseDn() {
return _configDao.getValue("ldap.basedn");
}
public String getBindPassword() {
return _configDao.getValue("ldap.bind.password");
}
public String getBindPrincipal() {
return _configDao.getValue("ldap.bind.principal");
}
public String getEmailAttribute() {
final String emailAttribute = _configDao
.getValue("ldap.email.attribute");
return emailAttribute == null ? "mail" : emailAttribute;
}
public String getFactory() {
return factory;
}
public String getFirstnameAttribute() {
final String firstnameAttribute = _configDao
.getValue("ldap.firstname.attribute");
return firstnameAttribute == null ? "givenname" : firstnameAttribute;
}
public String getLastnameAttribute() {
final String lastnameAttribute = _configDao
.getValue("ldap.lastname.attribute");
return lastnameAttribute == null ? "sn" : lastnameAttribute;
}
public String getProviderUrl() {
final String protocol = getSSLStatus() == true ? "ldaps://" : "ldap://";
final Pair<List<? extends LdapConfigurationVO>, Integer> result = _ldapManager
.listConfigurations(new LdapListConfigurationCmd(_ldapManager));
final StringBuilder providerUrls = new StringBuilder();
String delim = "";
for (final LdapConfigurationVO resource : result.first()) {
final String providerUrl = protocol + resource.getHostname() + ":"
+ resource.getPort();
providerUrls.append(delim).append(providerUrl);
delim = " ";
}
return providerUrls.toString();
}
public String[] getReturnAttributes() {
return new String[] { getUsernameAttribute(), getEmailAttribute(),
getFirstnameAttribute(), getLastnameAttribute() };
}
public int getScope() {
return scope;
}
public String getSearchGroupPrinciple() {
return _configDao.getValue("ldap.search.group.principle");
}
public boolean getSSLStatus() {
boolean sslStatus = false;
if (getTrustStore() != null && getTrustStorePassword() != null) {
sslStatus = true;
}
return sslStatus;
}
public String getTrustStore() {
return _configDao.getValue("ldap.truststore");
}
public String getTrustStorePassword() {
return _configDao.getValue("ldap.truststore.password");
}
public String getUsernameAttribute() {
final String usernameAttribute = _configDao
.getValue("ldap.username.attribute");
return usernameAttribute == null ? "uid" : usernameAttribute;
}
public String getUserObject() {
final String userObject = _configDao.getValue("ldap.user.object");
return userObject == null ? "inetOrgPerson" : userObject;
}
}

View File

@ -0,0 +1,66 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.cloudstack.api.InternalIdentity;
@Entity
@Table(name = "ldap_configuration")
public class LdapConfigurationVO implements InternalIdentity {
@Column(name = "hostname")
private String hostname;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "port")
private int port;
public LdapConfigurationVO() {
}
public LdapConfigurationVO(final String hostname, final int port) {
this.hostname = hostname;
this.port = port;
}
public String getHostname() {
return hostname;
}
@Override
public long getId() {
return id;
}
public int getPort() {
return port;
}
public void setId(final long id) {
this.id = id;
}
}

View File

@ -0,0 +1,136 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.Hashtable;
import javax.inject.Inject;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import org.apache.log4j.Logger;
public class LdapContextFactory {
private static final Logger s_logger = Logger
.getLogger(LdapContextFactory.class.getName());
@Inject
private LdapConfiguration _ldapConfiguration;
public LdapContextFactory() {
}
public LdapContextFactory(final LdapConfiguration ldapConfiguration) {
_ldapConfiguration = ldapConfiguration;
}
public DirContext createBindContext() throws NamingException {
return createBindContext(null);
}
public DirContext createBindContext(final String providerUrl)
throws NamingException {
final String bindPrincipal = _ldapConfiguration.getBindPrincipal();
final String bindPassword = _ldapConfiguration.getBindPassword();
return createInitialDirContext(bindPrincipal, bindPassword,
providerUrl, true);
}
private DirContext createInitialDirContext(final String principal,
final String password, final boolean isSystemContext)
throws NamingException {
return createInitialDirContext(principal, password, null,
isSystemContext);
}
private DirContext createInitialDirContext(final String principal,
final String password, final String providerUrl,
final boolean isSystemContext) throws NamingException {
return new InitialDirContext(getEnvironment(principal, password,
providerUrl, isSystemContext));
}
public DirContext createUserContext(final String principal,
final String password) throws NamingException {
return createInitialDirContext(principal, password, false);
}
private void enableSSL(final Hashtable<String, String> environment) {
final boolean sslStatus = _ldapConfiguration.getSSLStatus();
if (sslStatus) {
s_logger.info("LDAP SSL enabled.");
environment.put(Context.SECURITY_PROTOCOL, "ssl");
System.setProperty("javax.net.ssl.trustStore",
_ldapConfiguration.getTrustStore());
System.setProperty("javax.net.ssl.trustStorePassword",
_ldapConfiguration.getTrustStorePassword());
}
}
private Hashtable<String, String> getEnvironment(final String principal,
final String password, final String providerUrl,
final boolean isSystemContext) {
final String factory = _ldapConfiguration.getFactory();
final String url = providerUrl == null ? _ldapConfiguration
.getProviderUrl() : providerUrl;
final Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, factory);
environment.put(Context.PROVIDER_URL, url);
environment.put("com.sun.jndi.ldap.read.timeout", "500");
environment.put("com.sun.jndi.ldap.connect.pool", "true");
enableSSL(environment);
setAuthentication(environment, isSystemContext);
if (principal != null) {
environment.put(Context.SECURITY_PRINCIPAL, principal);
}
if (password != null) {
environment.put(Context.SECURITY_CREDENTIALS, password);
}
return environment;
}
private void setAuthentication(final Hashtable<String, String> environment,
final boolean isSystemContext) {
final String authentication = _ldapConfiguration.getAuthentication();
if ("none".equals(authentication) && !isSystemContext) {
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
} else {
environment.put(Context.SECURITY_AUTHENTICATION, authentication);
}
}
public void testConnection(final String providerUrl) throws NamingException {
try {
createBindContext(providerUrl);
s_logger.info("LDAP Connection was successful");
} catch (final NamingException e) {
s_logger.warn("LDAP Connection failed");
s_logger.error(e.getMessage(), e);
throw e;
}
}
}

View File

@ -0,0 +1,57 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.List;
import javax.naming.NamingException;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.Pair;
import com.cloud.utils.component.PluggableService;
public interface LdapManager extends PluggableService {
LdapConfigurationResponse addConfiguration(String hostname, int port)
throws InvalidParameterValueException;
boolean canAuthenticate(String username, String password);
LdapConfigurationResponse createLdapConfigurationResponse(
LdapConfigurationVO configuration);
LdapUserResponse createLdapUserResponse(LdapUser user);
LdapConfigurationResponse deleteConfiguration(String hostname)
throws InvalidParameterValueException;
LdapUser getUser(final String username) throws NamingException;
List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException;
boolean isLdapEnabled();
Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(
LdapListConfigurationCmd cmd);
List<LdapUser> searchUsers(String query)
throws NoLdapUserMatchingQueryException;
}

View File

@ -0,0 +1,232 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import org.apache.cloudstack.api.LdapValidator;
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd;
import org.apache.cloudstack.api.command.LdapCreateAccountCmd;
import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd;
import org.apache.cloudstack.api.command.LdapListConfigurationCmd;
import org.apache.cloudstack.api.command.LdapListUsersCmd;
import org.apache.cloudstack.api.command.LdapUserSearchCmd;
import org.apache.cloudstack.api.response.LdapConfigurationResponse;
import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.ldap.dao.LdapConfigurationDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.utils.Pair;
@Component
@Local(value = LdapManager.class)
public class LdapManagerImpl implements LdapManager, LdapValidator {
private static final Logger s_logger = Logger
.getLogger(LdapManagerImpl.class.getName());
@Inject
private LdapConfigurationDao _ldapConfigurationDao;
@Inject
private LdapContextFactory _ldapContextFactory;
@Inject
private LdapUserManager _ldapUserManager;
public LdapManagerImpl() {
super();
}
public LdapManagerImpl(final LdapConfigurationDao ldapConfigurationDao,
final LdapContextFactory ldapContextFactory,
final LdapUserManager ldapUserManager) {
super();
_ldapConfigurationDao = ldapConfigurationDao;
_ldapContextFactory = ldapContextFactory;
_ldapUserManager = ldapUserManager;
}
@Override
public LdapConfigurationResponse addConfiguration(final String hostname,
final int port) throws InvalidParameterValueException {
LdapConfigurationVO configuration = _ldapConfigurationDao
.findByHostname(hostname);
if (configuration == null) {
try {
final String providerUrl = "ldap://" + hostname + ":" + port;
_ldapContextFactory.createBindContext(providerUrl);
configuration = new LdapConfigurationVO(hostname, port);
_ldapConfigurationDao.persist(configuration);
s_logger.info("Added new ldap server with hostname: "
+ hostname);
return new LdapConfigurationResponse(hostname, port);
} catch (final NamingException e) {
throw new InvalidParameterValueException(
"Unable to bind to the given LDAP server");
}
} else {
throw new InvalidParameterValueException("Duplicate configuration");
}
}
@Override
public boolean canAuthenticate(final String username, final String password) {
final String escapedUsername = LdapUtils
.escapeLDAPSearchFilter(username);
try {
final LdapUser user = getUser(escapedUsername);
final String principal = user.getPrincipal();
final DirContext context = _ldapContextFactory.createUserContext(
principal, password);
closeContext(context);
return true;
} catch (final NamingException e) {
s_logger.info("Failed to authenticate user: " + username
+ ". incorrect password.");
return false;
}
}
private void closeContext(final DirContext context) {
try {
if (context != null) {
context.close();
}
} catch (final NamingException e) {
s_logger.warn(e.getMessage());
}
}
@Override
public LdapConfigurationResponse createLdapConfigurationResponse(
final LdapConfigurationVO configuration) {
final LdapConfigurationResponse response = new LdapConfigurationResponse();
response.setHostname(configuration.getHostname());
response.setPort(configuration.getPort());
return response;
}
@Override
public LdapUserResponse createLdapUserResponse(final LdapUser user) {
final LdapUserResponse response = new LdapUserResponse();
response.setUsername(user.getUsername());
response.setFirstname(user.getFirstname());
response.setLastname(user.getLastname());
response.setEmail(user.getEmail());
response.setPrincipal(user.getPrincipal());
return response;
}
@Override
public LdapConfigurationResponse deleteConfiguration(final String hostname)
throws InvalidParameterValueException {
final LdapConfigurationVO configuration = _ldapConfigurationDao
.findByHostname(hostname);
if (configuration == null) {
throw new InvalidParameterValueException(
"Cannot find configuration with hostname " + hostname);
} else {
_ldapConfigurationDao.remove(configuration.getId());
s_logger.info("Removed ldap server with hostname: " + hostname);
return new LdapConfigurationResponse(configuration.getHostname(),
configuration.getPort());
}
}
@Override
public List<Class<?>> getCommands() {
final List<Class<?>> cmdList = new ArrayList<Class<?>>();
cmdList.add(LdapUserSearchCmd.class);
cmdList.add(LdapListUsersCmd.class);
cmdList.add(LdapAddConfigurationCmd.class);
cmdList.add(LdapDeleteConfigurationCmd.class);
cmdList.add(LdapListConfigurationCmd.class);
cmdList.add(LdapCreateAccountCmd.class);
return cmdList;
}
@Override
public LdapUser getUser(final String username) throws NamingException {
DirContext context = null;
try {
context = _ldapContextFactory.createBindContext();
final String escapedUsername = LdapUtils
.escapeLDAPSearchFilter(username);
return _ldapUserManager.getUser(escapedUsername, context);
} catch (final NamingException e) {
throw e;
} finally {
closeContext(context);
}
}
@Override
public List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException {
DirContext context = null;
try {
context = _ldapContextFactory.createBindContext();
return _ldapUserManager.getUsers(context);
} catch (final NamingException e) {
throw new NoLdapUserMatchingQueryException("*");
} finally {
closeContext(context);
}
}
@Override
public boolean isLdapEnabled() {
return listConfigurations(new LdapListConfigurationCmd(this)).second() > 0;
}
@Override
public Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(
final LdapListConfigurationCmd cmd) {
final String hostname = cmd.getHostname();
final int port = cmd.getPort();
final Pair<List<LdapConfigurationVO>, Integer> result = _ldapConfigurationDao
.searchConfigurations(hostname, port);
return new Pair<List<? extends LdapConfigurationVO>, Integer>(
result.first(), result.second());
}
@Override
public List<LdapUser> searchUsers(final String username)
throws NoLdapUserMatchingQueryException {
DirContext context = null;
try {
context = _ldapContextFactory.createBindContext();
final String escapedUsername = LdapUtils
.escapeLDAPSearchFilter(username);
return _ldapUserManager.getUsers("*" + escapedUsername + "*",
context);
} catch (final NamingException e) {
throw new NoLdapUserMatchingQueryException(username);
} finally {
closeContext(context);
}
}
}

View File

@ -0,0 +1,77 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
public class LdapUser implements Comparable<LdapUser> {
private final String email;
private final String principal;
private final String firstname;
private final String lastname;
private final String username;
public LdapUser(final String username, final String email,
final String firstname, final String lastname,
final String principal) {
this.username = username;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.principal = principal;
}
@Override
public int compareTo(final LdapUser other) {
return getUsername().compareTo(other.getUsername());
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other instanceof LdapUser) {
final LdapUser otherLdapUser = (LdapUser) other;
return getUsername().equals(otherLdapUser.getUsername());
}
return false;
}
public String getEmail() {
return email;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public String getPrincipal() {
return principal;
}
public String getUsername() {
return username;
}
@Override
public int hashCode() {
return getUsername().hashCode();
}
}

View File

@ -0,0 +1,140 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LdapUserManager {
@Inject
private LdapConfiguration _ldapConfiguration;
public LdapUserManager() {
}
public LdapUserManager(final LdapConfiguration ldapConfiguration) {
_ldapConfiguration = ldapConfiguration;
}
private LdapUser createUser(final SearchResult result)
throws NamingException {
final Attributes attributes = result.getAttributes();
final String username = LdapUtils.getAttributeValue(attributes,
_ldapConfiguration.getUsernameAttribute());
final String email = LdapUtils.getAttributeValue(attributes,
_ldapConfiguration.getEmailAttribute());
final String firstname = LdapUtils.getAttributeValue(attributes,
_ldapConfiguration.getFirstnameAttribute());
final String lastname = LdapUtils.getAttributeValue(attributes,
_ldapConfiguration.getLastnameAttribute());
final String principal = result.getName() + ","
+ _ldapConfiguration.getBaseDn();
return new LdapUser(username, email, firstname, lastname, principal);
}
private String generateSearchFilter(final String username) {
final StringBuilder userObjectFilter = new StringBuilder();
userObjectFilter.append("(objectClass=");
userObjectFilter.append(_ldapConfiguration.getUserObject());
userObjectFilter.append(")");
final StringBuilder usernameFilter = new StringBuilder();
usernameFilter.append("(");
usernameFilter.append(_ldapConfiguration.getUsernameAttribute());
usernameFilter.append("=");
usernameFilter.append((username == null ? "*" : username));
usernameFilter.append(")");
final StringBuilder memberOfFilter = new StringBuilder();
if (_ldapConfiguration.getSearchGroupPrinciple() != null) {
memberOfFilter.append("(memberof=");
memberOfFilter.append(_ldapConfiguration.getSearchGroupPrinciple());
memberOfFilter.append(")");
}
final StringBuilder result = new StringBuilder();
result.append("(&");
result.append(userObjectFilter);
result.append(usernameFilter);
result.append(memberOfFilter);
result.append(")");
return result.toString();
}
public LdapUser getUser(final String username, final DirContext context)
throws NamingException {
final NamingEnumeration<SearchResult> result = searchUsers(username,
context);
if (result.hasMoreElements()) {
return createUser(result.nextElement());
} else {
throw new NamingException("No user found for username " + username);
}
}
public List<LdapUser> getUsers(final DirContext context)
throws NamingException {
return getUsers(null, context);
}
public List<LdapUser> getUsers(final String username,
final DirContext context) throws NamingException {
final NamingEnumeration<SearchResult> results = searchUsers(username,
context);
final List<LdapUser> users = new ArrayList<LdapUser>();
while (results.hasMoreElements()) {
final SearchResult result = results.nextElement();
users.add(createUser(result));
}
Collections.sort(users);
return users;
}
public NamingEnumeration<SearchResult> searchUsers(final DirContext context)
throws NamingException {
return searchUsers(null, context);
}
public NamingEnumeration<SearchResult> searchUsers(final String username,
final DirContext context) throws NamingException {
final SearchControls controls = new SearchControls();
controls.setSearchScope(_ldapConfiguration.getScope());
controls.setReturningAttributes(_ldapConfiguration
.getReturnAttributes());
return context.search(_ldapConfiguration.getBaseDn(),
generateSearchFilter(username), controls);
}
}

View File

@ -0,0 +1,62 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
public final class LdapUtils {
public static String escapeLDAPSearchFilter(final String filter) {
final StringBuilder sb = new StringBuilder();
for (final char character : filter.toCharArray()) {
switch (character) {
case '\\':
sb.append("\\5c");
break;
case '*':
sb.append("\\2a");
break;
case '(':
sb.append("\\28");
break;
case ')':
sb.append("\\29");
break;
case '\u0000':
sb.append("\\00");
break;
default:
sb.append(character);
}
}
return sb.toString();
}
public static String getAttributeValue(final Attributes attributes,
final String attributeName) throws NamingException {
final Attribute attribute = attributes.get(attributeName);
if (attribute != null) {
final Object value = attribute.get();
return String.valueOf(value);
}
return null;
}
private LdapUtils() {
}
}

View File

@ -0,0 +1,32 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap;
public class NoLdapUserMatchingQueryException extends Exception {
private static final long serialVersionUID = 7124360347208388174L;
private final String query;
public NoLdapUserMatchingQueryException(final String query) {
super("No users matching: " + query);
this.query = query;
}
public String getQuery() {
return query;
}
}

View File

@ -14,13 +14,18 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.response;
package org.apache.cloudstack.ldap;
import org.apache.cloudstack.api.BaseResponse;
public class NoSuchLdapUserException extends Exception {
private static final long serialVersionUID = 6782938919658010900L;
private final String username;
public class LDAPRemoveResponse extends BaseResponse {
public NoSuchLdapUserException(final String username) {
super("No such user: " + username);
this.username = username;
}
public LDAPRemoveResponse(){
super();
}
public String getUsername() {
return username;
}
}

View File

@ -0,0 +1,32 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap.dao;
import java.util.List;
import org.apache.cloudstack.ldap.LdapConfigurationVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
public interface LdapConfigurationDao extends
GenericDao<LdapConfigurationVO, Long> {
LdapConfigurationVO findByHostname(String hostname);
Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(
String hostname, int port);
}

View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.apache.cloudstack.ldap.dao;
import java.util.List;
import javax.ejb.Local;
import org.apache.cloudstack.ldap.LdapConfigurationVO;
import org.springframework.stereotype.Component;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
@Component
@Local(value = { LdapConfigurationDao.class })
public class LdapConfigurationDaoImpl extends
GenericDaoBase<LdapConfigurationVO, Long> implements
LdapConfigurationDao {
private final SearchBuilder<LdapConfigurationVO> hostnameSearch;
private final SearchBuilder<LdapConfigurationVO> listAllConfigurationsSearch;
public LdapConfigurationDaoImpl() {
super();
hostnameSearch = createSearchBuilder();
hostnameSearch.and("hostname", hostnameSearch.entity().getHostname(),
SearchCriteria.Op.EQ);
hostnameSearch.done();
listAllConfigurationsSearch = createSearchBuilder();
listAllConfigurationsSearch.and("hostname", listAllConfigurationsSearch
.entity().getHostname(), Op.EQ);
listAllConfigurationsSearch.and("port", listAllConfigurationsSearch
.entity().getPort(), Op.EQ);
listAllConfigurationsSearch.done();
}
@Override
public LdapConfigurationVO findByHostname(final String hostname) {
final SearchCriteria<LdapConfigurationVO> sc = hostnameSearch.create();
sc.setParameters("hostname", hostname);
return findOneBy(sc);
}
@Override
public Pair<List<LdapConfigurationVO>, Integer> searchConfigurations(
final String hostname, final int port) {
final SearchCriteria<LdapConfigurationVO> sc = listAllConfigurationsSearch
.create();
if (hostname != null) {
sc.setParameters("hostname", hostname);
}
return searchAndCount(sc, null);
}
}

View File

@ -0,0 +1,56 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import javax.naming.NamingEnumeration
import javax.naming.NamingException
import javax.naming.directory.SearchResult
class BasicNamingEnumerationImpl implements NamingEnumeration {
private LinkedList<String> items = new LinkedList<SearchResult>();
public void add(SearchResult item) {
items.add(item)
}
@Override
public void close() throws NamingException {
}
@Override
public boolean hasMore() throws NamingException {
return hasMoreElements();
}
@Override
public boolean hasMoreElements() {
return items.size != 0;
}
@Override
public Object next() throws NamingException {
return nextElement();
}
@Override
public Object nextElement() {
SearchResult result = items.getFirst();
items.removeFirst();
return result;
}
}

View File

@ -0,0 +1,89 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import com.cloud.exception.InvalidParameterValueException
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd
import org.apache.cloudstack.api.response.LdapConfigurationResponse
import org.apache.cloudstack.ldap.LdapManager
class LdapAddConfigurationCmdSpec extends spock.lang.Specification {
def "Test failed response from execute"() {
given: "We have an LDAP manager, no configuration and a LdapAddConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.addConfiguration(_, _) >> { throw new InvalidParameterValueException() }
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "LdapAddCofnigurationCmd is executed"
ldapAddConfigurationCmd.execute()
then: "an exception is thrown"
thrown ServerApiException
}
def "Test getEntityOwnerId is 1"() {
given: "We have an LdapManager and LdapConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "Get Entity Owner Id is called"
long ownerId = ldapAddConfigurationCmd.getEntityOwnerId()
then: "1 is returned"
ownerId == 1
}
def "Test successful response from execute"() {
given: "We have an LDAP Manager that has a configuration and a LdapAddConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.addConfiguration(_, _) >> new LdapConfigurationResponse("localhost", 389)
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "LdapAddConfigurationCmd is executed"
ldapAddConfigurationCmd.execute()
then: "the responseObject should have the hostname localhost and port 389"
ldapAddConfigurationCmd.responseObject.hostname == "localhost"
ldapAddConfigurationCmd.responseObject.port == 389
}
def "Test successful return of getCommandName"() {
given: "We have an LdapManager and LdapConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "Get Command Name is called"
String commandName = ldapAddConfigurationCmd.getCommandName()
then: "ldapconfigurationresponse is returned"
commandName == "ldapconfigurationresponse"
}
def "Test successful setting of hostname"() {
given: "We have an LdapManager and LdapAddConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "The hostname is set"
ldapAddConfigurationCmd.setHostname("localhost")
then: "Get hostname returns the set hostname"
ldapAddConfigurationCmd.getHostname() == "localhost"
}
def "Test successful setting of port"() {
given: "We have an LdapManager and LdapAddConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapAddConfigurationCmd = new LdapAddConfigurationCmd(ldapManager)
when: "The port is set"
ldapAddConfigurationCmd.setPort(389)
then: "Get port returns the port"
ldapAddConfigurationCmd.getPort() == 389
}
}

View File

@ -0,0 +1,99 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import com.cloud.user.UserAccountVO
import com.cloud.user.dao.UserAccountDao
import com.cloud.utils.Pair
import org.apache.cloudstack.ldap.LdapAuthenticator
import org.apache.cloudstack.ldap.LdapConfigurationVO
import org.apache.cloudstack.ldap.LdapManager
class LdapAuthenticatorSpec extends spock.lang.Specification {
def "Test a failed authentication due to user not being found within cloudstack"() {
given: "We have an LdapManager, userAccountDao and ldapAuthenticator and the user doesn't exist within cloudstack."
LdapManager ldapManager = Mock(LdapManager)
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> null
def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao)
when: "A user authentications"
def result = ldapAuthenticator.authenticate("rmurphy", "password", 0, null)
then: "their authentication fails"
result == false
}
def "Test failed authentication due to ldap bind being unsuccessful"() {
given: "We have an LdapManager, LdapConfiguration, userAccountDao and LdapAuthenticator"
def ldapManager = Mock(LdapManager)
ldapManager.isLdapEnabled() >> true
ldapManager.canAuthenticate(_, _) >> false
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao)
when: "The user authenticates with an incorrect password"
def result = ldapAuthenticator.authenticate("rmurphy", "password", 0, null)
then: "their authentication fails"
result == false
}
def "Test failed authentication due to ldap not being configured"() {
given: "We have an LdapManager, A configured LDAP server, a userAccountDao and LdapAuthenticator"
def ldapManager = Mock(LdapManager)
ldapManager.isLdapEnabled() >> false
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao)
when: "The user authenticates"
def result = ldapAuthenticator.authenticate("rmurphy", "password", 0, null)
then: "their authentication fails"
result == false
}
def "Test successful authentication"() {
given: "We have an LdapManager, LdapConfiguration, userAccountDao and LdapAuthenticator"
def ldapManager = Mock(LdapManager)
ldapManager.isLdapEnabled() >> true
ldapManager.canAuthenticate(_, _) >> true
UserAccountDao userAccountDao = Mock(UserAccountDao)
userAccountDao.getUserAccount(_, _) >> new UserAccountVO()
def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao)
when: "The user authenticates with an incorrect password"
def result = ldapAuthenticator.authenticate("rmurphy", "password", 0, null)
then: "their authentication passes"
result == true
}
def "Test that encode doesn't change the input"() {
given: "We have an LdapManager, userAccountDao and LdapAuthenticator"
LdapManager ldapManager = Mock(LdapManager)
UserAccountDao userAccountDao = Mock(UserAccountDao)
def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao)
when: "a users password is encoded"
def result = ldapAuthenticator.encode("password")
then: "it doesn't change"
result == "password"
}
}

View File

@ -0,0 +1,29 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl
class LdapConfigurationDaoImplSpec extends spock.lang.Specification {
def "Test setting up of a LdapConfigurationDao"() {
given: "We have an LdapConfigurationDao implementation"
def ldapConfigurationDaoImpl = new LdapConfigurationDaoImpl();
expect: "that hostnameSearch and listAllConfigurationsSearch is configured"
ldapConfigurationDaoImpl.hostnameSearch != null;
ldapConfigurationDaoImpl.listAllConfigurationsSearch != null
}
}

View File

@ -0,0 +1,49 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.api.response.LdapConfigurationResponse
class LdapConfigurationResponseSpec extends spock.lang.Specification {
def "Testing succcessful setting of LdapConfigurationResponse hostname"() {
given: "We have a LdapConfigurationResponse"
LdapConfigurationResponse response = new LdapConfigurationResponse();
when: "The hostname is set"
response.setHostname("localhost");
then: "Get hostname should return the set value"
response.getHostname() == "localhost";
}
def "Testing successful setting of LdapConfigurationResponse hostname and port via constructor"() {
given: "We have a LdapConfiguration response"
LdapConfigurationResponse response
when: "both hostname and port are set by constructor"
response = new LdapConfigurationResponse("localhost", 389)
then: "Get hostname and port should return the set values."
response.getHostname() == "localhost"
response.getPort() == 389
}
def "Testing successful setting of LdapConfigurationResponse port"() {
given: "We have a LdapConfigurationResponse"
LdapConfigurationResponse response = new LdapConfigurationResponse()
when: "The port is set"
response.setPort(389)
then: "Get port should return the set value"
response.getPort() == 389
}
}

View File

@ -0,0 +1,223 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.utils.Pair
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.ldap.LdapConfiguration
import org.apache.cloudstack.ldap.LdapConfigurationVO
import org.apache.cloudstack.ldap.LdapManager
import javax.naming.directory.SearchControls
class LdapConfigurationSpec extends spock.lang.Specification {
def "Test that getAuthentication returns none"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get authentication is called"
String authentication = ldapConfiguration.getAuthentication()
then: "none should be returned"
authentication == "none"
}
def "Test that getAuthentication returns simple"() {
given: "We have a configDao, LdapManager and LdapConfiguration with bind principle and password set"
def configDao = Mock(ConfigurationDao)
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
configDao.getValue("ldap.bind.password") >> "password"
configDao.getValue("ldap.bind.principal") >> "cn=rmurphy,dc=cloudstack,dc=org"
when: "Get authentication is called"
String authentication = ldapConfiguration.getAuthentication()
then: "authentication should be set to simple"
authentication == "simple"
}
def "Test that getBaseDn returns dc=cloudstack,dc=org"() {
given: "We have a ConfigDao, LdapManager and ldapConfiguration with a baseDn value set."
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.basedn") >> "dc=cloudstack,dc=org"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get basedn is called"
String baseDn = ldapConfiguration.getBaseDn();
then: "The set baseDn should be returned"
baseDn == "dc=cloudstack,dc=org"
}
def "Test that getEmailAttribute returns mail"() {
given: "Given that we have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.email.attribute") >> "mail"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get Email Attribute is called"
String emailAttribute = ldapConfiguration.getEmailAttribute()
then: "mail should be returned"
emailAttribute == "mail"
}
def "Test that getFactory returns com.sun.jndi.ldap.LdapCtxFactory"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get Factory is scalled"
String factory = ldapConfiguration.getFactory();
then: "com.sun.jndi.ldap.LdapCtxFactory is returned"
factory == "com.sun.jndi.ldap.LdapCtxFactory"
}
def "Test that getFirstnameAttribute returns givenname"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.firstname.attribute") >> "givenname"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get firstname attribute is called"
String firstname = ldapConfiguration.getFirstnameAttribute()
then: "givennam should be returned"
firstname == "givenname"
}
def "Test that getLastnameAttribute returns givenname"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.lastname.attribute") >> "sn"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get Lastname Attribute is scalled "
String lastname = ldapConfiguration.getLastnameAttribute()
then: "sn should be returned"
lastname == "sn"
}
def "Test that getReturnAttributes returns the correct data"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.firstname.attribute") >> "givenname"
configDao.getValue("ldap.lastname.attribute") >> "sn"
configDao.getValue("ldap.username.attribute") >> "uid"
configDao.getValue("ldap.email.attribute") >> "mail"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get return attributes is called"
String[] returnAttributes = ldapConfiguration.getReturnAttributes()
then: "An array containing uid, mail, givenname and sn is returned"
returnAttributes == ["uid", "mail", "givenname", "sn"]
}
def "Test that getScope returns SearchControls.SUBTREE_SCOPE"() {
given: "We have ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get scope is called"
int scope = ldapConfiguration.getScope()
then: "SearchControls.SUBTRE_SCOPE should be returned"
scope == SearchControls.SUBTREE_SCOPE;
}
def "Test that getUsernameAttribute returns uid"() {
given: "We have ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.username.attribute") >> "uid"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get Username Attribute is called"
String usernameAttribute = ldapConfiguration.getUsernameAttribute()
then: "uid should be returned"
usernameAttribute == "uid"
}
def "Test that getUserObject returns inetOrgPerson"() {
given: "We have a ConfigDao, LdapManager and LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.user.object") >> "inetOrgPerson"
def ldapManager = Mock(LdapManager)
def ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "Get user object is called"
String userObject = ldapConfiguration.getUserObject()
then: "inetOrgPerson is returned"
userObject == "inetOrgPerson"
}
def "Test that providerUrl successfully returns a URL when a configuration is available"() {
given: "We have a ConfigDao, LdapManager, LdapConfiguration"
def configDao = Mock(ConfigurationDao)
def ldapManager = Mock(LdapManager)
List<LdapConfigurationVO> ldapConfigurationList = new ArrayList()
ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389))
Pair<List<LdapConfigurationVO>, Integer> result = new Pair<List<LdapConfigurationVO>, Integer>();
result.set(ldapConfigurationList, ldapConfigurationList.size())
ldapManager.listConfigurations(_) >> result
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "A request is made to get the providerUrl"
String providerUrl = ldapConfiguration.getProviderUrl()
then: "The providerUrl should be given."
providerUrl == "ldap://localhost:389"
}
def "Test that get search group principle returns successfully"() {
given: "We have a ConfigDao with a value for ldap.search.group.principle and an LdapConfiguration"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.search.group.principle") >> "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
def ldapManager = Mock(LdapManager)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "A request is made to get the search group principle"
String result = ldapConfiguration.getSearchGroupPrinciple();
then: "The result holds the same value configDao did"
result == "cn=cloudstack,cn=users,dc=cloudstack,dc=org"
}
def "Test that getTrustStorePassword resopnds"() {
given: "We have a ConfigDao with a value for truststore password"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.truststore.password") >> "password"
def ldapManager = Mock(LdapManager)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "A request is made to get the truststore password"
String result = ldapConfiguration.getTrustStorePassword()
then: "The result is password"
result == "password";
}
def "Test that getSSLStatus can be true"() {
given: "We have a ConfigDao with values for truststore and truststore password set"
def configDao = Mock(ConfigurationDao)
configDao.getValue("ldap.truststore") >> "/tmp/ldap.ts"
configDao.getValue("ldap.truststore.password") >> "password"
def ldapManager = Mock(LdapManager)
LdapConfiguration ldapConfiguration = new LdapConfiguration(configDao, ldapManager)
when: "A request is made to get the status of SSL"
boolean result = ldapConfiguration.getSSLStatus();
then: "The response should be true"
result == true
}
}

View File

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapConfigurationVO
class LdapConfigurationVOSpec extends spock.lang.Specification {
def "Testing that the ID hostname and port is correctly set within the LDAP configuration VO"() {
given: "You have created an LDAP Configuration VO"
def configuration = new LdapConfigurationVO(hostname, port)
configuration.setId(id)
expect: "The id hostname and port is equal to the given data source"
configuration.getId() == id
configuration.getHostname() == hostname
configuration.getPort() == port
where: "The id, hostname and port is set to "
hostname << ["", null, "localhost"]
id << [0, 1000, -1000]
port << [0, 1000, -1000]
}
}

View File

@ -0,0 +1,127 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapConfiguration
import org.apache.cloudstack.ldap.LdapContextFactory
import spock.lang.Shared
import javax.naming.NamingException
import javax.naming.directory.SearchControls
import javax.naming.ldap.LdapContext
class LdapContextFactorySpec extends spock.lang.Specification {
@Shared
private def ldapConfiguration
@Shared
private def username
@Shared
private def principal
@Shared
private def password
def setupSpec() {
ldapConfiguration = Mock(LdapConfiguration)
ldapConfiguration.getFactory() >> "com.sun.jndi.ldap.LdapCtxFactory"
ldapConfiguration.getProviderUrl() >> "ldap://localhost:389"
ldapConfiguration.getAuthentication() >> "none"
ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
ldapConfiguration.getReturnAttributes() >> ["uid", "mail", "cn"]
ldapConfiguration.getUsernameAttribute() >> "uid"
ldapConfiguration.getEmailAttribute() >> "mail"
ldapConfiguration.getFirstnameAttribute() >> "givenname"
ldapConfiguration.getLastnameAttribute() >> "sn"
ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
ldapConfiguration.getSSLStatus() >> true
ldapConfiguration.getTrustStore() >> "/tmp/ldap.ts"
ldapConfiguration.getTrustStorePassword() >> "password"
username = "rmurphy"
principal = "cn=" + username + "," + ldapConfiguration.getBaseDn()
password = "password"
}
def "Test succcessfully creating a initial context"() {
given: "We have a LdapContextFactory"
def ldapContextFactory = new LdapContextFactory(ldapConfiguration)
when: "A context attempts to bind and no Ldap server is avaiable"
ldapContextFactory.createInitialDirContext(null, null, true)
then: "An expection is thrown"
thrown NamingException
}
def "Test successful failed connection"() {
given: "We have a LdapContextFactory"
def ldapContextFactory = Spy(LdapContextFactory, constructorArgs: [ldapConfiguration])
when: "Test connection is executed"
ldapContextFactory.testConnection(ldapConfiguration.getProviderUrl())
then: "An exception is thrown"
thrown NamingException
}
def "Test successfully binding as a user"() {
given: "We have a LdapContextFactory"
def ldapContextFactory = new LdapContextFactory(ldapConfiguration)
when: "A user attempts to bind and no LDAP server is avaiable"
ldapContextFactory.createUserContext(principal, password)
then: "An exception is thrown"
thrown NamingException
}
def "Test successfully creating a environment with username and password"() {
given: "We have an LdapContextFactory"
def ldapContextFactory = new LdapContextFactory(ldapConfiguration)
when: "A request for an environment is made"
def result = ldapContextFactory.getEnvironment(null, null, null, true)
then: "The resulting values should be set"
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
result['java.naming.security.principal'] == null
result['java.naming.security.authentication'] == ldapConfiguration.getAuthentication()
result['java.naming.security.credentials'] == null
}
def "Test successfully creating a system environment with anon bind"() {
given: "We have an LdapContext Factory"
def ldapContextFactory = new LdapContextFactory(ldapConfiguration)
when: "A request for an environment is made"
def result = ldapContextFactory.getEnvironment(principal, password, null, false)
then: "The resulting values should be set"
result['java.naming.provider.url'] == ldapConfiguration.getProviderUrl()
result['java.naming.factory.initial'] == ldapConfiguration.getFactory()
result['java.naming.security.principal'] == principal
result['java.naming.security.authentication'] == "simple"
result['java.naming.security.credentials'] == password
}
def "Test successully binding as system"() {
given: "We have a LdapContextFactory"
def ldapContextFactory = new LdapContextFactory(ldapConfiguration)
when: "A bind context attempts to bind and no Ldap server is avaiable"
ldapContextFactory.createBindContext()
then: "An exception is thrown"
thrown NamingException
}
}

View File

@ -0,0 +1,155 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import com.cloud.exception.InvalidParameterValueException
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapAddConfigurationCmd
import org.apache.cloudstack.api.response.LdapConfigurationResponse
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.api.command.LdapCreateAccountCmd;
import org.apache.cloudstack.context.CallContext;
import com.cloud.user.AccountService;
import com.cloud.user.UserAccount;
import com.cloud.user.UserAccountVO;
import javax.naming.NamingException
class LdapCreateAccountCmdSpec extends spock.lang.Specification {
def "Test failure to retrive LDAP user"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd and LDAP user that doesn't exist"
LdapManager ldapManager = Mock(LdapManager)
ldapManager.getUser(_) >> { throw new NamingException() }
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
CallContext context = ldapCreateAccountCmd.getCurrentContext()
when: "An an account is created"
ldapCreateAccountCmd.execute()
then: "It fails and an exception is thrown"
thrown ServerApiException
}
def "Test failed creation due to a null response from cloudstack account creater"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
ldapManager.getUser(_) >> new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext)
ldapCreateAccountCmd.createCloudstackUserAccount(_) >> null
when: "Cloudstack fail to create the user"
ldapCreateAccountCmd.execute()
then: "An exception is thrown"
thrown ServerApiException
}
def "Test command name"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "Get command name is called"
def result = ldapCreateAccountCmd.getCommandName()
then: "createaccountresponse is returned"
result == "createaccountresponse"
}
def "Test getEntityOwnerId is 1"() {
given: "We have an LdapManager, AccountService andL dapCreateAccount"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
when: "Get entity owner id is called"
long ownerId = ldapCreateAccountCmd.getEntityOwnerId()
then: "1 is returned"
ownerId == 1
}
def "Test password generation"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A password is generated"
def result = ldapCreateAccountCmd.generatePassword()
then: "The result shouldn't be null or empty"
result != ""
result != null
}
def "Test validate User"() {
given: "We have an LdapManager, AccountService andL dapCreateAccount"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService);
when: "a user with an username, email, firstname and lastname is validated"
def result = ldapCreateAccountCmd.validateUser(new LdapUser("username","email","firstname","lastname","principal"))
then: "the result is true"
result == true
}
def "Test validate User empty email"() {
given: "We have an LdapManager, AccountService andL dapCreateAccount"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A user with no email address attempts to validate"
ldapCreateAccountCmd.validateUser(new LdapUser("username",null,"firstname","lastname","principal"))
then: "An exception is thrown"
thrown Exception
}
def "Test validate User empty firstname"() {
given: "We have an LdapManager, AccountService andL dapCreateAccount"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A user with no firstname attempts to validate"
ldapCreateAccountCmd.validateUser(new LdapUser("username","email",null,"lastname","principal"))
then: "An exception is thrown"
thrown Exception
}
def "Test validate User empty lastname"() {
given: "We have an LdapManager, AccountService and LdapCreateAccountCmd"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = new LdapCreateAccountCmd(ldapManager, accountService)
when: "A user with no lastname attempts to validate"
ldapCreateAccountCmd.validateUser(new LdapUser("username","email","firstname",null,"principal"))
then: "An exception is thown"
thrown Exception
}
def "Test validation of a user"() {
given: "We have an LdapManager, AccountService andL dapCreateAccount"
LdapManager ldapManager = Mock(LdapManager)
AccountService accountService = Mock(AccountService)
def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService])
when: "Get command name is called"
def commandName = ldapCreateAccountCmd.getCommandName()
then: "createaccountresponse is returned"
commandName == "createaccountresponse"
}
}

View File

@ -0,0 +1,68 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import com.cloud.exception.InvalidParameterValueException
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd
import org.apache.cloudstack.api.response.LdapConfigurationResponse
import org.apache.cloudstack.ldap.LdapManager
class LdapDeleteConfigurationCmdSpec extends spock.lang.Specification {
def "Test failed response from execute"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.deleteConfiguration(_) >> { throw new InvalidParameterValueException() }
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when:"LdapDeleteConfigurationCmd is executed and no configuration exists"
ldapDeleteConfigurationCmd.execute()
then: "An exception is thrown"
thrown ServerApiException
}
def "Test getEntityOwnerId is 1"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when: "Get entity owner id is called"
long ownerId = ldapDeleteConfigurationCmd.getEntityOwnerId()
then: "1 is returned"
ownerId == 1
}
def "Test successful response from execute"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
ldapManager.deleteConfiguration(_) >> new LdapConfigurationResponse("localhost")
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when: "LdapDeleteConfigurationCmd is executed"
ldapDeleteConfigurationCmd.execute()
then: "The given configuration should be deleted and returned"
ldapDeleteConfigurationCmd.responseObject.hostname == "localhost"
}
def "Test successful return of getCommandName"() {
given: "We have an LdapManager and LdapDeleteConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapDeleteConfigurationCmd = new LdapDeleteConfigurationCmd(ldapManager)
when: "Get Command name is called"
String commandName = ldapDeleteConfigurationCmd.getCommandName()
then: "ldapconfigurationresponse is returned"
commandName == "ldapconfigurationresponse"
}
}

View File

@ -0,0 +1,98 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapListConfigurationCmd
import org.apache.cloudstack.api.response.LdapConfigurationResponse
import org.apache.cloudstack.ldap.LdapConfigurationVO
import org.apache.cloudstack.ldap.LdapManager
import com.cloud.utils.Pair
class LdapListConfigurationCmdSpec extends spock.lang.Specification {
def "Test failed response from execute"() {
given: "We have an LdapManager and a LdapListConfigurationsCmd"
def ldapManager = Mock(LdapManager)
List<LdapConfigurationVO> ldapConfigurationList = new ArrayList()
Pair<List<LdapConfigurationVO>, Integer> ldapConfigurations = new Pair<List<LdapConfigurationVO>, Integer>();
ldapConfigurations.set(ldapConfigurationList, ldapConfigurationList.size())
ldapManager.listConfigurations(_) >> ldapConfigurations
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "LdapListConfigurationCmd is executed"
ldapListConfigurationCmd.execute()
then: "Its response object contains an array that is 0"
ldapListConfigurationCmd.getResponseObject().getResponses().size() == 0
}
def "Test getEntityOwnerId is 1"() {
given: "We have an LdapManager and ListLdapConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "Get entity owner id is called"
long ownerId = ldapListConfigurationCmd.getEntityOwnerId()
then: "a 1 is returned"
ownerId == 1
}
def "Test successful response from execute"() {
given: "We have an LdapManager with a configuration and a LdapListConfigurationsCmd"
def ldapManager = Mock(LdapManager)
List<LdapConfigurationVO> ldapConfigurationList = new ArrayList()
ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389))
Pair<List<LdapConfigurationVO>, Integer> ldapConfigurations = new Pair<List<LdapConfigurationVO>, Integer>();
ldapConfigurations.set(ldapConfigurationList, ldapConfigurationList.size())
ldapManager.listConfigurations(_) >> ldapConfigurations
ldapManager.createLdapConfigurationResponse(_) >> new LdapConfigurationResponse("localhost", 389)
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "LdapListConfigurationsCmd is executed"
ldapListConfigurationCmd.execute()
then: "Its response object contains an array that is not 0 in size"
ldapListConfigurationCmd.getResponseObject().getResponses().size() != 0
}
def "Test successful return of getCommandName"() {
given: "We have an LdapManager and LdapListConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "Get command name is called"
String commandName = ldapListConfigurationCmd.getCommandName()
then: "ldapconfigurationresponse is returned"
commandName == "ldapconfigurationresponse"
}
def "Test successful setting of hostname"() {
given: "We have an LdapManager and LdapListConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "The hostname is set"
ldapListConfigurationCmd.setHostname("localhost")
then: "Get hostname returns the set value"
ldapListConfigurationCmd.getHostname() == "localhost"
}
def "Test successful setting of Port"() {
given: "We have an LdapManager and LdapListConfigurationCmd"
def ldapManager = Mock(LdapManager)
def ldapListConfigurationCmd = new LdapListConfigurationCmd(ldapManager)
when: "The port is set"
ldapListConfigurationCmd.setPort(389)
then: "Get port returns the set value"
ldapListConfigurationCmd.getPort() == 389
}
}

View File

@ -0,0 +1,123 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.api.command.LdapListUsersCmd
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd
import org.apache.cloudstack.api.response.LdapUserResponse
import org.apache.cloudstack.api.response.ListResponse
import org.apache.cloudstack.api.response.UserResponse
import org.apache.cloudstack.ldap.LdapManager
import org.apache.cloudstack.ldap.LdapUser
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException
import org.apache.cloudstack.query.QueryService
class LdapListUsersCmdSpec extends spock.lang.Specification {
def "Test getEntityOwnerId is 1"() {
given: "We have an LdapManager, QueryService and LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
def queryService = Mock(QueryService)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
when: "Get entity owner id is called"
long ownerId = ldapListUsersCmd.getEntityOwnerId()
then: "a 1 should be returned"
ownerId == 1
}
def "Test successful empty response from execute"() {
given: "We have a LdapManager with no users, QueryService and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
ldapManager.getUsers() >> {throw new NoLdapUserMatchingQueryException()}
def queryService = Mock(QueryService)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
when: "LdapListUsersCmd is executed"
ldapListUsersCmd.execute()
then: "An array of size 0 is returned"
ldapListUsersCmd.responseObject.getResponses().size() == 0
}
def "Test successful response from execute"() {
given: "We have an LdapManager, one user, QueryService and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org"))
ldapManager.getUsers() >> users
LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
ldapManager.createLdapUserResponse(_) >> response
def queryService = Mock(QueryService)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
when: "LdapListUsersCmd is executed"
ldapListUsersCmd.execute()
then: "a list of size not 0 is returned"
ldapListUsersCmd.responseObject.getResponses().size() != 0
}
def "Test successful return of getCommandName"() {
given: "We have an LdapManager, QueryService and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
def queryService = Mock(QueryService)
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService)
when: "Get command name is called"
String commandName = ldapListUsersCmd.getCommandName()
then: "ldapuserresponse is returned"
commandName == "ldapuserresponse"
}
def "Test successful result from isACloudstackUser"() {
given: "We have an LdapManager and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
def queryService = Mock(QueryService)
UserResponse userResponse = new UserResponse()
userResponse.setUsername("rmurphy")
ArrayList<UserResponse> responses = new ArrayList<UserResponse>()
responses.add(userResponse);
ListResponse<UserResponse> queryServiceResponse = new ListResponse<UserResponse>()
queryServiceResponse.setResponses(responses)
queryService.searchForUsers(_) >> queryServiceResponse
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
when: "isACloudstackUser is executed"
def result = ldapListUsersCmd.isACloudstackUser(ldapUser);
then: "The result is true"
result == true;
}
def "Test failed result from isACloudstackUser"() {
given: "We have an LdapManager and a LdapListUsersCmd"
def ldapManager = Mock(LdapManager)
def queryService = Mock(QueryService)
queryService.searchForUsers(_) >> new ListResponse<UserResponse>()
def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService)
when: "isACloudstackUser is executed"
def result = ldapListUsersCmd.isACloudstackUser(ldapUser);
then: "The result is true"
result == false;
}
}

View File

@ -0,0 +1,336 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import javax.naming.NamingException
import javax.naming.ldap.InitialLdapContext
import org.apache.cloudstack.api.command.LdapListConfigurationCmd
import org.apache.cloudstack.ldap.*
import org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl
import com.cloud.exception.InvalidParameterValueException
import com.cloud.utils.Pair
class LdapManagerImplSpec extends spock.lang.Specification {
def "Test failing of getUser due to bind issue"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> { throw new NamingException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for a user but there is a bind issue"
ldapManager.getUser("rmurphy")
then: "an exception is thrown"
thrown NamingException
}
def "Test failing of getUsers due to bind issue"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> { throw new NamingException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for a group of users but there is a bind issue"
ldapManager.getUsers()
then: "An exception is thrown"
thrown NoLdapUserMatchingQueryException
}
def "Test failing of searchUsers due to a failure to bind"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> { throw new NamingException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for users"
ldapManager.searchUsers("rmurphy")
then: "An exception is thrown"
thrown NoLdapUserMatchingQueryException
}
def "Test LdapConfigurationResponse generation"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A ldap configuration response is generated"
def result = ldapManager.createLdapConfigurationResponse(new LdapConfigurationVO("localhost", 389))
then: "the result of the response should match the given LdapConfigurationVO"
result.hostname == "localhost"
result.port == 389
}
def "Test LdapUserResponse generation"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A ldap user response is generated"
def result = ldapManager.createLdapUserResponse(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org"))
then: "The result of the response should match the given ldap user"
result.username == "rmurphy"
result.email == "rmurphy@test.com"
result.firstname == "Ryan"
result.lastname == "Murphy"
result.principal == "cn=rmurphy,dc=cloudstack,dc=org"
}
def "Test success getUsers"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> null
List<LdapUser> users = new ArrayList<>();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org"))
ldapUserManager.getUsers(_) >> users;
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for a group of users"
def result = ldapManager.getUsers()
then: "A list greater than 0 is returned"
result.size() > 0;
}
def "Test success of getUser"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> null
ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for a user"
def result = ldapManager.getUser("rmurphy")
then: "The user is returned"
result.username == "rmurphy"
result.email == "rmurphy@test.com"
result.firstname == "Ryan"
result.lastname == "Murphy"
result.principal == "cn=rmurphy,dc=cloudstack,dc=org"
}
def "Test successful closing of context"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "The context is closed"
def context = Mock(InitialLdapContext)
ldapManager.closeContext(context)
then: "The context is null"
context.defaultInitCtx == null
}
def "Test successful failed result from canAuthenticate due to bad password"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
ldapContextFactory.createUserContext(_, _) >> { throw new NamingException() }
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager])
ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org") }
when: "The user attempts to authenticate with a bad password"
def result = ldapManager.canAuthenticate("rmurphy", "password")
then: "The authentication fails"
result == false
}
def "Test successful failed result from canAuthenticate due to user not found"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager])
ldapManager.getUser(_) >> { throw new NamingException() }
when: "The user attempts to authenticate and the user is not found"
def result = ldapManager.canAuthenticate("rmurphy", "password")
then: "the authentication fails"
result == false
}
def "Test successful failed result from deleteConfiguration due to configuration not existing"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapConfigurationDao.findByHostname(_) >> null
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A ldap configuration that doesn't exist is deleted"
ldapManager.deleteConfiguration("localhost")
then: "A exception is thrown"
thrown InvalidParameterValueException
}
def "Test successful failing to close of context"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "The context is closed"
def context = Mock(InitialLdapContext)
context.close() >> { throw new NamingException() }
ldapManager.closeContext(context)
then: "An exception is thrown"
context.defaultInitCtx == null
}
def "Test successful result from canAuthenticate"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
ldapContextFactory.createUserContext(_, _) >> null
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManager])
ldapManager.getUser(_) >> { new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org") }
when: "A user authenticates"
def result = ldapManager.canAuthenticate("rmurphy", "password")
then: "The result is true"
result == true
}
def "Test successful result from deleteConfiguration"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapConfigurationDao.findByHostname(_) >> {
def configuration = new LdapConfigurationVO("localhost", 389)
configuration.setId(0);
return configuration;
}
ldapConfigurationDao.remove(_) >> null
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A ldap configuration is deleted"
def result = ldapManager.deleteConfiguration("localhost")
then: "The deleted configuration is returned"
result.hostname == "localhost"
result.port == 389
}
def "Test successful result from searchUsers"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext() >> null;
List<LdapUser> users = new ArrayList<LdapUser>();
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org"))
ldapUserManager.getUsers(_, _) >> users;
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "We search for users"
def result = ldapManager.searchUsers("rmurphy");
then: "A list of atleast 1 is returned"
result.size() > 0;
}
def "Test successfully addConfiguration"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext(_) >> null
ldapConfigurationDao.persist(_) >> null
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A ldap configuration is added"
def result = ldapManager.addConfiguration("localhost", 389)
then: "the resulting object contain the given hostname and port"
result.hostname == "localhost"
result.port == 389
}
def "Test that addConfiguration fails when a binding fails"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapContextFactory.createBindContext(_) >> { throw new NamingException() }
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A configuration is added that can not be binded"
ldapManager.addConfiguration("localhost", 389)
then: "An exception is thrown"
thrown InvalidParameterValueException
}
def "Test that addConfiguration fails when a duplicate configuration exists"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
ldapConfigurationDao.findByHostname(_) >> new LdapConfigurationVO("localhost", 389)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "a configuration that already exists is added"
ldapManager.addConfiguration("localhost", 389)
then: "An exception is thrown"
thrown InvalidParameterValueException
}
def "Test that getCommands isn't empty"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "Get commands is called"
def result = ldapManager.getCommands()
then: "it must have atleast 1 command"
result.size() > 0
}
def "Testing of listConfigurations"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
List<LdapConfigurationVO> ldapConfigurationList = new ArrayList()
ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389))
Pair<List<LdapConfigurationVO>, Integer> configurations = new Pair<List<LdapConfigurationVO>, Integer>();
configurations.set(ldapConfigurationList, ldapConfigurationList.size())
ldapConfigurationDao.searchConfigurations(_, _) >> configurations
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A request for configurations is made"
def result = ldapManager.listConfigurations(new LdapListConfigurationCmd())
then: "Then atleast 1 ldap configuration is returned"
result.second() > 0
}
def "Testing of isLdapEnabled"() {
given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager"
def ldapConfigurationDao = Mock(LdapConfigurationDaoImpl)
def ldapContextFactory = Mock(LdapContextFactory)
def ldapUserManager = Mock(LdapUserManager)
List<LdapConfigurationVO> ldapConfigurationList = new ArrayList()
ldapConfigurationList.add(new LdapConfigurationVO("localhost", 389))
Pair<List<LdapConfigurationVO>, Integer> configurations = new Pair<List<LdapConfigurationVO>, Integer>();
configurations.set(ldapConfigurationList, ldapConfigurationList.size())
ldapConfigurationDao.searchConfigurations(_, _) >> configurations
def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManager)
when: "A request to find out is ldap enabled"
def result = ldapManager.isLdapEnabled();
then: "true is returned because a configuration was found"
result == true;
}
}

View File

@ -0,0 +1,72 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.api.ServerApiException
import org.apache.cloudstack.api.command.LdapUserSearchCmd
import org.apache.cloudstack.api.response.LdapUserResponse
import org.apache.cloudstack.ldap.LdapManager
import org.apache.cloudstack.ldap.LdapUser
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException
class LdapSearchUserCmdSpec extends spock.lang.Specification {
def "Test getEntityOwnerId is 1"() {
given: "We have an Ldap manager and ldap user search cmd"
def ldapManager = Mock(LdapManager)
def ldapUserSearchCmd = new LdapUserSearchCmd(ldapManager)
when: "getEntityOwnerId is called"
long ownerId = ldapUserSearchCmd.getEntityOwnerId()
then: "1 is returned"
ownerId == 1
}
def "Test successful empty response from execute"() {
given: "We have an Ldap manager and ldap user search cmd"
def ldapManager = Mock(LdapManager)
ldapManager.searchUsers(_) >> {throw new NoLdapUserMatchingQueryException()}
def ldapUserSearchCmd = new LdapUserSearchCmd(ldapManager)
when: "The command is executed with no users found"
ldapUserSearchCmd.execute()
then: "An empty array is returned"
ldapUserSearchCmd.responseObject.getResponses().size() == 0
}
def "Test successful response from execute"() {
given: "We have an Ldap manager and ldap user search cmd"
def ldapManager = Mock(LdapManager)
List<LdapUser> users = new ArrayList()
users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org"))
ldapManager.searchUsers(_) >> users
LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org")
ldapManager.createLdapUserResponse(_) >> response
def ldapUserSearchCmd = new LdapUserSearchCmd(ldapManager)
when: "The command is executed"
ldapUserSearchCmd.execute()
then: "A array with length of atleast 1 is returned"
ldapUserSearchCmd.responseObject.getResponses().size() > 0
}
def "Test successful return of getCommandName"() {
given: "We have an Ldap manager and ldap user search cmd"
def ldapManager = Mock(LdapManager)
def ldapUserSearchCmd = new LdapUserSearchCmd(ldapManager)
when: "When a request for the command name is made"
String commandName = ldapUserSearchCmd.getCommandName()
then: "ldapuserresponse is returned"
commandName == "ldapuserresponse"
}
}

View File

@ -0,0 +1,206 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapConfiguration
import org.apache.cloudstack.ldap.LdapUserManager
import spock.lang.Shared
import javax.naming.NamingException
import javax.naming.directory.Attribute
import javax.naming.directory.Attributes
import javax.naming.directory.SearchControls
import javax.naming.directory.SearchResult
import javax.naming.ldap.LdapContext
class LdapUserManagerSpec extends spock.lang.Specification {
@Shared
private def ldapConfiguration
@Shared
private def username
@Shared
private def email
@Shared
private def firstname
@Shared
private def lastname
@Shared
private def principal
private def createContext() {
Attributes attributes = createUserAttributes(username, email, firstname, lastname)
SearchResult searchResults = createSearchResult(attributes)
def searchUsersResults = new BasicNamingEnumerationImpl()
searchUsersResults.add(searchResults);
def context = Mock(LdapContext)
context.search(_, _, _) >> searchUsersResults;
return context
}
private SearchResult createSearchResult(attributes) {
def search = Mock(SearchResult)
search.getName() >> "cn=" + attributes.getAt("uid").get();
search.getAttributes() >> attributes
return search
}
private Attributes createUserAttributes(String username, String email, String firstname, String lastname) {
def attributes = Mock(Attributes)
def nameAttribute = Mock(Attribute)
nameAttribute.getId() >> "uid"
nameAttribute.get() >> username
attributes.get("uid") >> nameAttribute
def mailAttribute = Mock(Attribute)
mailAttribute.getId() >> "mail"
mailAttribute.get() >> email
attributes.get("mail") >> mailAttribute
def givennameAttribute = Mock(Attribute)
givennameAttribute.getId() >> "givenname"
givennameAttribute.get() >> firstname
attributes.get("givenname") >> givennameAttribute
def snAttribute = Mock(Attribute)
snAttribute.getId() >> "sn"
snAttribute.get() >> lastname
attributes.get("sn") >> snAttribute
return attributes
}
def setupSpec() {
ldapConfiguration = Mock(LdapConfiguration)
ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE
ldapConfiguration.getReturnAttributes() >> ["uid", "mail", "cn"]
ldapConfiguration.getUsernameAttribute() >> "uid"
ldapConfiguration.getEmailAttribute() >> "mail"
ldapConfiguration.getFirstnameAttribute() >> "givenname"
ldapConfiguration.getLastnameAttribute() >> "sn"
ldapConfiguration.getBaseDn() >> "dc=cloudstack,dc=org"
username = "rmurphy"
email = "rmurphy@test.com"
firstname = "Ryan"
lastname = "Murphy"
principal = "cn=" + username + "," + ldapConfiguration.getBaseDn()
}
def "Test successfully creating an Ldap User from Search result"() {
given: "We have attributes, a search and a user manager"
def attributes = createUserAttributes(username, email, firstname, lastname)
def search = createSearchResult(attributes)
def userManager = new LdapUserManager(ldapConfiguration)
def result = userManager.createUser(search)
expect: "The crated user the data supplied from LDAP"
result.username == username
result.email == email
result.firstname == firstname
result.lastname == lastname
result.principal == principal
}
def "Test successfully returning a list from get users"() {
given: "We have a LdapUserManager"
def userManager = new LdapUserManager(ldapConfiguration)
when: "A request for users is made"
def result = userManager.getUsers(username, createContext())
then: "A list of users is returned"
result.size() == 1
}
def "Test successfully returning a list from get users when no username is given"() {
given: "We have a LdapUserManager"
def userManager = new LdapUserManager(ldapConfiguration)
when: "Get users is called without a username"
def result = userManager.getUsers(createContext())
then: "All users are returned"
result.size() == 1
}
def "Test successfully returning a NamingEnumeration from searchUsers"() {
given: "We have a LdapUserManager"
def userManager = new LdapUserManager(ldapConfiguration)
when: "We search for users"
def result = userManager.searchUsers(createContext())
then: "A list of users are returned."
result.next().getName() + "," + ldapConfiguration.getBaseDn() == principal
}
def "Test successfully returning an Ldap user from a get user request"() {
given: "We have a LdapUserMaanger"
def userManager = new LdapUserManager(ldapConfiguration)
when: "A request for a user is made"
def result = userManager.getUser(username, createContext())
then: "The user is returned"
result.username == username
result.email == email
result.firstname == firstname
result.lastname == lastname
result.principal == principal
}
def "Test successfully throwing an exception when no users are found with getUser"() {
given: "We have a seachResult of users and a User Manager"
def searchUsersResults = new BasicNamingEnumerationImpl()
def context = Mock(LdapContext)
context.search(_, _, _) >> searchUsersResults;
def userManager = new LdapUserManager(ldapConfiguration)
when: "a get user request is made and no user is found"
def result = userManager.getUser(username, context)
then: "An exception is thrown."
thrown NamingException
}
def "Test that a newly created Ldap User Manager is not null"() {
given: "You have created a new Ldap user manager object"
def result = new LdapUserManager();
expect: "The result is not null"
result != null
}
}

View File

@ -0,0 +1,67 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.api.response.LdapUserResponse
class LdapUserResponseSpec extends spock.lang.Specification {
def "Testing succcessful setting of LdapUserResponse email"() {
given: "We have an LdapResponse"
LdapUserResponse response = new LdapUserResponse();
when: "An email address is set"
response.setEmail("rmurphy@test.com");
then: "Get email should return that set email"
response.getEmail() == "rmurphy@test.com";
}
def "Testing successful setting of LdapUserResponse firstname"() {
given: "We have an LdapUserResponse"
LdapUserResponse response = new LdapUserResponse()
when: "A firstname is set"
response.setFirstname("Ryan")
then: "gGet Firstname returns the set value"
response.getFirstname() == "Ryan"
}
def "Testing successful setting of LdapUserResponse lastname"() {
given: "We have an LdapUserResponse"
LdapUserResponse response = new LdapUserResponse()
when: "A lastname is set"
response.setLastname("Murphy")
then: "Get lastname is returned"
response.getLastname() == "Murphy"
}
def "Testing successful setting of LdapUserResponse principal"() {
given: "We have an LdapResponse"
LdapUserResponse response = new LdapUserResponse()
when: "A principal is set"
response.setPrincipal("dc=cloudstack,dc=org")
then: "Get principled returns the set value"
response.getPrincipal() == "dc=cloudstack,dc=org"
}
def "Testing successful setting of LdapUserResponse username"() {
given: "We have an LdapUserResponse"
LdapUserResponse response = new LdapUserResponse()
when: "A username is set"
response.setUsername("rmurphy")
then: "Get username returns the set value."
response.getUsername() == "rmurphy"
}
}

View File

@ -0,0 +1,101 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapUser
class LdapUserSpec extends spock.lang.Specification {
def "Testing LdapUsers hashCode generation"() {
given:
def userA = new LdapUser(usernameA, "", "", "", "")
expect:
userA.hashCode() == usernameA.hashCode()
where:
usernameA = "A"
}
def "Testing that LdapUser successfully gives the correct result for a compare to"() {
given: "You have created two LDAP user objects"
def userA = new LdapUser(usernameA, "", "", "", "")
def userB = new LdapUser(usernameB, "", "", "", "")
expect: "That when compared the result is less than or equal to 0"
userA.compareTo(userB) <= 0
where: "The following values are used"
usernameA | usernameB
"A" | "B"
"A" | "A"
}
def "Testing that LdapUsers equality"() {
given:
def userA = new LdapUser(usernameA, "", "", "", "")
def userB = new LdapUser(usernameB, "", "", "", "")
expect:
userA.equals(userA) == true
userA.equals(new Object()) == false
userA.equals(userB) == false
where:
usernameA | usernameB
"A" | "B"
}
def "Testing that the username is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a username"
def user = new LdapUser(username, "", "", "","")
expect: "The username is equal to the given data source"
user.getUsername() == username
where: "The username is set to "
username << ["", null, "rmurphy"]
}
def "Testing the email is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a email"
def user = new LdapUser("", email, "", "","")
expect: "The email is equal to the given data source"
user.getEmail() == email
where: "The email is set to "
email << ["", null, "test@test.com"]
}
def "Testing the firstname is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a firstname"
def user = new LdapUser("", "", firstname, "", "")
expect: "The firstname is equal to the given data source"
user.getFirstname() == firstname
where: "The firstname is set to "
firstname << ["", null, "Ryan"]
}
def "Testing the lastname is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a lastname"
def user = new LdapUser("", "", "", lastname, "")
expect: "The lastname is equal to the given data source"
user.getLastname() == lastname
where: "The lastname is set to "
lastname << ["", null, "Murphy"]
}
def "Testing the principal is correctly set with the ldap object"() {
given: "You have created a LDAP user object with a principal"
def user = new LdapUser("", "", "", "", principal)
expect: "The principal is equal to the given data source"
user.getPrincipal() == principal
where: "The username is set to "
principal << ["", null, "cn=rmurphy,dc=cloudstack,dc=org"]
}
}

View File

@ -0,0 +1,68 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.LdapUtils
import javax.naming.directory.Attribute
import javax.naming.directory.Attributes
class LdapUtilsSpec extends spock.lang.Specification {
def "Testing than an attribute is not successfully returned"() {
given: "You have an attributes object with some attribute"
def attributes = Mock(Attributes)
attributes.get("uid") >> null
when: "You get the attribute"
String foundValue = LdapUtils.getAttributeValue(attributes, "uid")
then: "Its value equals uid"
foundValue == null
}
def "Testing than an attribute is successfully returned"() {
given: "You have an attributes object with some attribute"
def attributes = Mock(Attributes)
def attribute = Mock(Attribute)
attribute.getId() >> name
attribute.get() >> value
attributes.get(name) >> attribute
when: "You get the attribute"
String foundValue = LdapUtils.getAttributeValue(attributes, name)
then: "Its value equals uid"
foundValue == value
where:
name | value
"uid" | "rmurphy"
"email" | "rmurphy@test.com"
}
def "Testing that a Ldap Search Filter is correctly escaped"() {
given: "You have some input from a user"
expect: "That the input is escaped"
LdapUtils.escapeLDAPSearchFilter(input) == result
where: "The following inputs are given "
input | result
"Hi This is a test #çà" | "Hi This is a test #çà"
"Hi (This) = is * a \\ test # ç à ô \u0000" | "Hi \\28This\\29 = is \\2a a \\5c test # ç à ô \\00"
}
}

View File

@ -0,0 +1,30 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException
class NoLdapUserMatchingQueryExceptionSpec extends spock.lang.Specification {
def "Test that the query is correctly set within the No LDAP user matching query exception object"() {
given: "You have created an No LDAP user matching query exception object with a query set"
def exception = new NoLdapUserMatchingQueryException(query)
expect: "The username is equal to the given data source"
exception.getQuery() == query
where: "The username is set to "
query << ["", null, "murp*"]
}
}

View File

@ -0,0 +1,30 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 groovy.org.apache.cloudstack.ldap
import org.apache.cloudstack.ldap.NoSuchLdapUserException;
class NoSuchLdapUserExceptionSpec extends spock.lang.Specification {
def "Test that the username is correctly set within the No such LDAP user exception object"() {
given: "You have created an No such LDAP user exception object with the username set"
def exception = new NoSuchLdapUserException(username)
expect: "The username is equal to the given data source"
exception.getUsername() == username
where: "The username is set to "
username << ["", null, "rmurphy"]
}
}

View File

@ -0,0 +1,295 @@
version: 1
dn: dc=cloudstack,dc=org
objectClass: dcObject
objectClass: organization
dc: cloudstack
o: cloudstack
dn: cn=Ryan Murphy,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Ryan Murphy
sn: Murphy
givenName: Ryan
mail: rmurphy@cloudstack.org
uid: rmurphy
userpassword:: cGFzc3dvcmQ=
dn: cn=Barbara Brewer,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Barbara Brewer
sn: Brewer
mail: bbrewer@cloudstack.org
uid: bbrewer
userpassword:: cGFzc3dvcmQ=
dn: cn=Zak Wilkinson,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Zak Wilkinson
givenname: Zak
sn: Wilkinson
uid: zwilkinson
userpassword:: cGFzc3dvcmQ=
dn: cn=Archie Shingleton,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Archie Shingleton
sn: Shingleton
givenName: Archie
mail: ashingleton@cloudstack.org
uid: ashingleton
userpassword:: cGFzc3dvcmQ=
dn: cn=Cletus Pears,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Cletus Pears
sn: Pears
givenName: Cletus
mail: cpears@cloudstack.org
uid: cpears
userpassword:: cGFzc3dvcmQ=
dn: cn=Teisha Milewski,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Teisha Milewski
sn: Milewski
givenName: Teisha
mail: tmilewski@cloudstack.org
uid: tmilewski
userpassword:: cGFzc3dvcmQ=
dn: cn=Eloy Para,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Eloy Para
sn: Para
givenName: Eloy
mail: epara@cloudstack.org
uid: epara
userpassword:: cGFzc3dvcmQ=
dn: cn=Elaine Lamb,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Elaine Lamb
sn: Lamb
givenName: Elaine
mail: elamb@cloudstack.org
uid: elamb
userpassword:: cGFzc3dvcmQ=
dn: cn=Soon Griffen,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Soon Griffen
sn: Griffen
givenName: Soon
mail: sgriffen@cloudstack.org
uid: sgriffen
userpassword:: cGFzc3dvcmQ=
dn: cn=Tran Neisler,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Tran Neisler
sn: Neisler
givenName: Tran
mail: tneisler@cloudstack.org
uid: tneisler
userpassword:: cGFzc3dvcmQ=
dn: cn=Mirella Zeck,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Mirella Zeck
sn: Zeck
givenName: Mirella
mail: mzeck@cloudstack.org
uid: mzeck
userpassword:: cGFzc3dvcmQ=
dn: cn=Greg Hoskin,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Greg Hoskin
sn: Hoskin
givenName: Greg
mail: ghoskin@cloudstack.org
uid: ghoskin
userpassword:: cGFzc3dvcmQ=
dn: cn=Johanne Runyon,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Johanne Runyon
sn: Runyon
givenName: Johanne
mail: jrunyon@cloudstack.org
uid: jrunyon
userpassword:: cGFzc3dvcmQ=
dn: cn=Mabelle Waiters,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Mabelle Waiters
sn: Waiters
givenName: Mabelle
mail: mwaiters@cloudstack.org
uid: mwaiters
userpassword:: cGFzc3dvcmQ=
dn: cn=Phillip Fruge,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Phillip Fruge
sn: Fruge
givenName: Phillip
mail: pfruge@cloudstack.org
uid: pfruge
userpassword:: cGFzc3dvcmQ=
dn: cn=Jayna Ridenhour,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Jayna Ridenhour
sn: Ridenhour
givenName: Jayna
mail: jridenhour@cloudstack.org
uid: jridenhour
userpassword:: cGFzc3dvcmQ=
dn: cn=Marlyn Mandujano,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Marlyn Mandujano
sn: Mandujano
givenName: Marlyn
mail: mmandujano@cloudstack.org
uid: mmandujano
userpassword:: cGFzc3dvcmQ=
dn: cn=Shaunna Scherer,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Shaunna Scherer
sn: Scherer
givenName: Shaunna
mail: sscherer@cloudstack.org
uid: sscherer
userpassword:: cGFzc3dvcmQ=
dn: cn=Adriana Bozek,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Adriana Bozek
sn: Bozek
givenName: Adriana
mail: abozek@cloudstack.org
uid: abozek
userpassword:: cGFzc3dvcmQ=
dn: cn=Silvana Chipman,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Silvana Chipman
sn: Chipman
givenName: Silvana
mail: schipman@cloudstack.org
uid: schipman
userpassword:: cGFzc3dvcmQ=
dn: cn=Marion Wasden,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Marion Wasden
sn: Wasden
givenName: Marion
mail: mwasden@cloudstack.org
uid: mwasden
userpassword:: cGFzc3dvcmQ=
dn: cn=Anisa Casson,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Anisa Casson
sn: Casson
givenName: Anisa
mail: acasson@cloudstack.org
uid: acasson
userpassword:: cGFzc3dvcmQ=
dn: cn=Noel King,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Noel King
sn: King
givenName: Noel
mail: nking@cloudstack.org
uid: nking
userpassword:: cGFzc3dvcmQ=
dn: cn=Cammy Petri,dc=cloudstack,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Cammy Petri
sn: Petri
givenName: Cammy
mail: cpetri@cloudstack.org
uid: cpetri
userpassword:: cGFzc3dvcmQ=

View File

@ -81,7 +81,6 @@ import org.apache.cloudstack.api.response.LBHealthCheckPolicyResponse;
import org.apache.cloudstack.api.response.LBHealthCheckResponse;
import org.apache.cloudstack.api.response.LBStickinessPolicyResponse;
import org.apache.cloudstack.api.response.LBStickinessResponse;
import org.apache.cloudstack.api.response.LDAPConfigResponse;
import org.apache.cloudstack.api.response.LoadBalancerResponse;
import org.apache.cloudstack.api.response.NetworkACLItemResponse;
import org.apache.cloudstack.api.response.NetworkACLResponse;
@ -2804,20 +2803,6 @@ public class ApiResponseHelper implements ResponseGenerator {
return hcResponse;
}
@Override
public LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String searchBase,
String bindDN) {
LDAPConfigResponse lr = new LDAPConfigResponse();
lr.setHostname(hostname);
lr.setPort(port.toString());
lr.setUseSSL(useSSL.toString());
lr.setQueryFilter(queryFilter);
lr.setBindDN(bindDN);
lr.setSearchBase(searchBase);
lr.setObjectName("ldapconfig");
return lr;
}
@Override
public StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result) {
StorageNetworkIpRangeResponse response = new StorageNetworkIpRangeResponse();

View File

@ -415,6 +415,19 @@ public enum Config {
// object store
S3EnableRRS("Advanced", ManagementServer.class, Boolean.class, "s3.rrs.enabled", "false", "enable s3 reduced redundancy storage", null),
// Ldap
LdapBasedn("Advanced", ManagementServer.class, String.class, "ldap.basedn", null, "Sets the basedn for LDAP", null),
LdapBindPassword("Advanced", ManagementServer.class, String.class, "ldap.bind.password", null, "Sets the bind password for LDAP", null),
LdapBindPrincipal("Advanced", ManagementServer.class, String.class, "ldap.bind.principal", null, "Sets the bind principal for LDAP", null),
LdapEmailAttribute("Advanced", ManagementServer.class, String.class, "ldap.email.attribute", "mail", "Sets the email attribute used within LDAP", null),
LdapFirstnameAttribute("Advanced", ManagementServer.class, String.class, "ldap.firstname.attribute", "givenname", "Sets the firstname attribute used within LDAP", null),
LdapLastnameAttribute("Advanced", ManagementServer.class, String.class, "ldap.lastname.attribute", "sn", "Sets the lastname attribute used within LDAP", null),
LdapUsernameAttribute("Advanced", ManagementServer.class, String.class, "ldap.username.attribute", "uid", "Sets the username attribute used within LDAP", null),
LdapUserObject("Advanced", ManagementServer.class, String.class, "ldap.user.object", "inetOrgPerson", "Sets the object type of users within LDAP", null),
LdapSearchGroupPrinciple("Advanced", ManagementServer.class, String.class, "ldap.search.group.principle", null, "Sets the principle of the group that users must be a member of", null),
LdapTrustStore("Advanced", ManagementServer.class, String.class, "ldap.truststore", null, "Sets the path to the truststore to use for SSL", null),
LdapTrustStorePassword("Advanced", ManagementServer.class, String.class, "ldap.truststore.password", null, "Sets the password for the truststore", null),
// VMSnapshots
VMSnapshotMax("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.max", "10", "Maximum vm snapshots for a vm", null),
VMSnapshotCreateWait("Advanced", VMSnapshotManager.class, Integer.class, "vmsnapshot.create.wait", "1800", "In second, timeout for create vm snapshot", null),
@ -423,15 +436,15 @@ public enum Config {
BlacklistedRoutes("Advanced", VpcManager.class, String.class, "blacklisted.routes", null, "Routes that are blacklisted, can not be used for Static Routes creation for the VPC Private Gateway",
"routes", ConfigurationParameterScope.zone.toString()),
InternalLbVmServiceOfferingId("Advanced", ManagementServer.class, String.class, "internallbvm.service.offering", null, "Uuid of the service offering used by internal lb vm; if NULL - default system internal lb offering will be used", null),
ExecuteInSequence("Advanced", ManagementServer.class, Boolean.class, "execute.in.sequence.hypervisor.commands", "false", "If set to true, StartCommand, StopCommand, CopyCommand will be synchronized on the agent side." +
" If set to false, these commands become asynchronous. Default value is false.", null),
ExecuteInSequenceNetworkElementCommands("Advanced", NetworkManager.class, Boolean.class, "execute.in.sequence.network.element.commands", "false", "If set to true, DhcpEntryCommand, SavePasswordCommand, UserDataCommand, VmDataCommand will be synchronized on the agent side." +
" If set to false, these commands become asynchronous. Default value is false.", null),
UCSSyncBladeInterval("Advanced", ManagementServer.class, Integer.class, "ucs.sync.blade.interval", "3600", "the interval cloudstack sync with UCS manager for available blades in case user remove blades from chassis without notifying CloudStack", null);
private final String _category;
private final Class<?> _componentClass;
private final Class<?> _type;

View File

@ -41,10 +41,7 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiConstants.LDAPParams;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
@ -1547,175 +1544,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
@Override
@DB
public boolean removeLDAP(LDAPRemoveCmd cmd) {
_configDao.expunge(LDAPParams.hostname.toString());
_configDao.expunge(LDAPParams.port.toString());
_configDao.expunge(LDAPParams.queryfilter.toString());
_configDao.expunge(LDAPParams.searchbase.toString());
_configDao.expunge(LDAPParams.usessl.toString());
_configDao.expunge(LDAPParams.dn.toString());
_configDao.expunge(LDAPParams.passwd.toString());
_configDao.expunge(LDAPParams.truststore.toString());
_configDao.expunge(LDAPParams.truststorepass.toString());
return true;
}
@Override
@DB
public LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd) {
String hostname = _configDao.getValue(LDAPParams.hostname.toString());
cmd.setHostname(hostname == null ? "" : hostname);
String port = _configDao.getValue(LDAPParams.port.toString());
cmd.setPort(port == null ? 0 : Integer.valueOf(port));
String queryFilter = _configDao.getValue(LDAPParams.queryfilter.toString());
cmd.setQueryFilter(queryFilter == null ? "" : queryFilter);
String searchBase = _configDao.getValue(LDAPParams.searchbase.toString());
cmd.setSearchBase(searchBase == null ? "" : searchBase);
String useSSL = _configDao.getValue(LDAPParams.usessl.toString());
cmd.setUseSSL(useSSL == null ? Boolean.FALSE : Boolean.valueOf(useSSL));
String binddn = _configDao.getValue(LDAPParams.dn.toString());
cmd.setBindDN(binddn == null ? "" : binddn);
String truststore = _configDao.getValue(LDAPParams.truststore.toString());
cmd.setTrustStore(truststore == null ? "" : truststore);
return cmd;
}
@Override
@DB
public boolean updateLDAP(LDAPConfigCmd cmd) {
try {
// set the ldap details in the zone details table with a zone id of
// -12
String hostname = cmd.getHostname();
Integer port = cmd.getPort();
String queryFilter = cmd.getQueryFilter();
String searchBase = cmd.getSearchBase();
Boolean useSSL = cmd.getUseSSL();
String bindDN = cmd.getBindDN();
String bindPasswd = cmd.getBindPassword();
String trustStore = cmd.getTrustStore();
String trustStorePassword = cmd.getTrustStorePassword();
if (bindDN != null && bindPasswd == null) {
throw new InvalidParameterValueException(
"If you specify a bind name then you need to provide bind password too.");
}
// check query filter if it contains valid substitution
if (!queryFilter.contains("%u") && !queryFilter.contains("%n") && !queryFilter.contains("%e")) {
throw new InvalidParameterValueException(
"QueryFilter should contain at least one of the substitutions: %u, %n or %e: " + queryFilter);
}
// check if the info is correct
Hashtable<String, String> env = new Hashtable<String, String>(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
String protocol = "ldap://";
if (useSSL) {
env.put(Context.SECURITY_PROTOCOL, "ssl");
protocol = "ldaps://";
if (trustStore == null || trustStorePassword == null) {
throw new InvalidParameterValueException(
"If you plan to use SSL then you need to configure the trust store.");
}
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
}
env.put(Context.PROVIDER_URL, protocol + hostname + ":" + port);
if (bindDN != null && bindPasswd != null) {
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, bindDN);
env.put(Context.SECURITY_CREDENTIALS, bindPasswd);
}
// Create the initial context
DirContext ctx = new InitialDirContext(env);
ctx.close();
// store the result in DB Configuration
ConfigurationVO cvo = _configDao.findByName(LDAPParams.hostname.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.hostname.toString(),
null, "Hostname or ip address of the ldap server eg: my.ldap.com");
}
cvo.setValue(DBEncryptionUtil.encrypt(hostname));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.port.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.port.toString(), null,
"Specify the LDAP port if required, default is 389");
}
cvo.setValue(DBEncryptionUtil.encrypt(port.toString()));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.queryfilter.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.queryfilter.toString(),
null,
"You specify a query filter here, which narrows down the users, who can be part of this domain");
}
cvo.setValue(DBEncryptionUtil.encrypt(queryFilter));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.searchbase.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.searchbase.toString(),
null,
"The search base defines the starting point for the search in the directory tree Example: dc=cloud,dc=com.");
}
cvo.setValue(DBEncryptionUtil.encrypt(searchBase));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.usessl.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.usessl.toString(), null,
"Check Use SSL if the external LDAP server is configured for LDAP over SSL.");
}
cvo.setValue(DBEncryptionUtil.encrypt(useSSL.toString()));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.dn.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.dn.toString(), null,
"Specify the distinguished name of a user with the search permission on the directory");
}
cvo.setValue(DBEncryptionUtil.encrypt(bindDN));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.passwd.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.passwd.toString(), null,
"Enter the password");
}
cvo.setValue(DBEncryptionUtil.encrypt(bindPasswd));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.truststore.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server", LDAPParams.truststore.toString(),
null, "Enter the path to trusted keystore");
}
cvo.setValue(DBEncryptionUtil.encrypt(trustStore));
_configDao.persist(cvo);
cvo = _configDao.findByName(LDAPParams.truststorepass.toString());
if (cvo == null) {
cvo = new ConfigurationVO("Hidden", "DEFAULT", "management-server",
LDAPParams.truststorepass.toString(), null, "Enter the password for trusted keystore");
}
cvo.setValue(DBEncryptionUtil.encrypt(trustStorePassword));
_configDao.persist(cvo);
s_logger.debug("The ldap server is configured: " + hostname);
} catch (NamingException ne) {
throw new InvalidParameterValueException("Naming Exception, check you ldap data ! " + ne.getMessage()
+ (ne.getCause() != null ? ("; Caused by:" + ne.getCause().getMessage()) : ""));
}
return true;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "editing zone", async = false)

View File

@ -90,8 +90,6 @@ import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd;
import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalancerElementsCmd;
import org.apache.cloudstack.api.command.admin.internallb.StartInternalLBVMCmd;
import org.apache.cloudstack.api.command.admin.internallb.StopInternalLBVMCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd;
import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
@ -2521,8 +2519,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(ReconnectHostCmd.class);
cmdList.add(UpdateHostCmd.class);
cmdList.add(UpdateHostPasswordCmd.class);
cmdList.add(LDAPConfigCmd.class);
cmdList.add(LDAPRemoveCmd.class);
cmdList.add(AddNetworkDeviceCmd.class);
cmdList.add(AddNetworkServiceProviderCmd.class);
cmdList.add(CreateNetworkOfferingCmd.class);

View File

@ -28,8 +28,6 @@ import javax.naming.NamingException;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
@ -318,33 +316,6 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
return null;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#updateLDAP(org.apache.cloudstack.api.commands.LDAPConfigCmd)
*/
@Override
public boolean updateLDAP(LDAPConfigCmd cmd) throws NamingException {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#removeLDAP(org.apache.cloudstack.api.commands.LDAPRemoveCmd)
*/
@Override
public boolean removeLDAP(LDAPRemoveCmd cmd) {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#listLDAPConfig(org.apache.cloudstack.api.commands.LDAPConfigCmd)
*/
@Override
public LDAPConfigCmd listLDAPConfig(LDAPConfigCmd cmd) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#isOfferingForVpc(com.cloud.offering.NetworkOffering)
*/
@ -576,4 +547,4 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
}
}
}

View File

@ -2307,3 +2307,23 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Storage', 'DEFAULT', 'manage
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Storage', 'DEFAULT', 'management-server', 'storage.cache.replacement.interval', '86400', 'time interval between cache replacement threads (in seconds).');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ("Advanced", 'DEFAULT', 'management-server', 'vmware.nested.virtualization', 'false', 'When set to true this will enable nested virtualization when this is supported by the hypervisor');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.bind.principal', NULL, 'Specifies the bind principal to use for bind to LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.bind.password', NULL, 'Specifies the password to use for binding to LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.username.attribute', 'uid', 'Sets the username attribute used within LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.email.attribute', 'mail', 'Sets the email attribute used within LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.firstname.attribute', 'givenname', 'Sets the firstname attribute used within LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.lastname.attribute', 'sn', 'Sets the lastname attribute used within LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.user.object', 'inetOrgPerson', 'Sets the object type of users within LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.basedn', NULL, 'Sets the basedn for LDAP');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.search.group.principle', NULL, 'Sets the principle of the group that users must be a member of');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.truststore', NULL, 'Sets the path to the truststore to use for LDAP SSL');
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'ldap.truststore.password', NULL, 'Sets the password for the truststore');
CREATE TABLE `cloud`.`ldap_configuration` (
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
`hostname` varchar(255) NOT NULL COMMENT 'the hostname of the ldap server',
`port` int(10) COMMENT 'port that the ldap server is listening on',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -44,78 +44,30 @@ class Services:
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "test",
"lastname": "t",
"username": "test",
"password": "password",
"email": "rmurphy@cloudstack.org",
"firstname": "Ryan",
"lastname": "Murphy",
"username": "rmurphy",
"password": "internalcloudstackpassword",
},
"ldapCon_1":#valid values&Query filter as email.
"ldapConfiguration_1":
{
"ldapHostname": "10.147.38.163",
"port": "389",
"binddn": "CN=test,CN=Users,DC=hyd-qa,DC=com",
"bindpass": "aaaa_1111",
"queryfilter": "(&(mail=%e))",
"searchbase": "CN=Users,DC=hyd-qa,DC=com",
"ldapusername": "test",
"ldappasswd": "aaaa_1111"
},
"ldapCon_2": ##valid values&Query filter as displayName.
{
"ldapHostname": "10.147.38.163",
"port": "389",
"binddn": "CN=test,CN=Users,DC=hyd-qa,DC=com",
"bindpass": "aaaa_1111",
"queryfilter": "(&(displayName=%u))",
"searchbase": "CN=Users,DC=hyd-qa,DC=com",
"ldapusername": "test",
"ldappasswd": "aaaa_1111"
},
"ldapCon_3": #Configuration with missing parameters value(queryfilter)
{
"ldapHostname": "10.147.38.163",
"port": "389",
"binddn": "CN=test,CN=Users,DC=hyd-qa,DC=com",
"bindpass": "aaaa_1111",
"queryfilter": "",
"searchbase": "CN=Users,DC=hyd-qa,DC=com",
"ldapusername": "test",
"ldappasswd": "aaaa_1111"
},
"ldapCon_4": #invalid configuration-wrong query filter
{
"ldapHostname": "10.147.38.163",
"port": "389",
"binddn": "CN=test,CN=Users,DC=hyd-qa,DC=com",
"bindpass": "aaaa_1111",
"queryfilter": "(&(displayName=%p))",
"searchbase":"CN=Users,DC=hyd-qa,DC=com",
"ldapusername": "test",
"ldappasswd": "aaaa_1111"
},
"ldapCon_5": #Configuration with invalid ldap credentials
{
"ldapHostname": "10.147.38.163",
"port": "389",
"binddn": "CN=test,CN=Users,DC=hyd-qa,DC=com",
"bindpass": "aaaa_1111",
"queryfilter": "(&(displayName=%u))",
"searchbase": "CN=Users,DC=hyd-qa,DC=com",
"ldapusername": "test",
"ldappasswd": "aaaa"
"basedn": "dc=cloudstack,dc=org",
"emailAttribute": "mail",
"realnameAttribute": "cn",
"userObject": "inetOrgPerson",
"usernameAttribute": "uid",
"hostname": "localhost",
"port": "10389",
"ldapUsername": "rmurphy",
"ldapPassword": "password"
}
}
class TestLdap(cloudstackTestCase):
"""
This test perform registering ldap configuration details in CS and create a user[ldap user] in CS
and validate user credentials against LDAP server:AD
This tests attempts to register a LDAP server and authenticate as an LDAP user.
"""
@classmethod
@ -134,8 +86,6 @@ class TestLdap(cloudstackTestCase):
@classmethod
def tearDownClass(cls):
try:
#Cleanup resources used
#print "tear down class"
cleanup_resources(cls.api_client, cls._cleanup)
except Exception as tde:
@ -144,10 +94,10 @@ class TestLdap(cloudstackTestCase):
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.apiClient = self.testClient.getApiClient()
self.acct = createAccount.createAccountCmd()
self.acct.accounttype = 0 #We need a regular user. admins have accounttype=1
self.acct.accounttype = 0
self.acct.firstname = self.services["account"]["firstname"]
self.acct.lastname = self.services["account"]["lastname"]
self.acct.password = self.services["account"]["password"]
@ -155,208 +105,153 @@ class TestLdap(cloudstackTestCase):
self.acct.email = self.services["account"]["email"]
self.acct.account = self.services["account"]["username"]
self.acct.domainid = 1
# mapping ldap user by creating same user in cloudstack
self.acctRes = self.apiclient.createAccount(self.acct)
self.acctRes = self.apiClient.createAccount(self.acct)
return
def tearDown(self):
try:
#Clean up, terminate the created accounts, domains etc
deleteAcct = deleteAccount.deleteAccountCmd()
deleteAcct.id = self.acctRes.id
acct_name=self.acctRes.name
self.apiclient.deleteAccount(deleteAcct)
self.apiClient.deleteAccount(deleteAcct)
self.debug("Deleted the the following account name %s:" %acct_name)
#delete only if ldapconfig registered in CS
if(self.ldapconfRes):
deleteldapconfg=ldapRemove.ldapRemoveCmd()
res=self.apiclient.ldapRemove(deleteldapconfg)
if(self.ldapconfRes==1):
self._deleteLdapConfiguration(self.services["ldapConfiguration_1"])
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@attr(tags=["advanced", "basic"])
def test_01_configLDAP(self):
'''
This test is to verify ldapConfig API with valid values.(i.e query fileter as email)
'''
# 1. This test covers ldapConfig & login API with valid ldap credentials..
# require ldap configuration:ldapCon_1
def test_01_addLdapConfiguration(self):
"""
This test configures LDAP and attempts to authenticate as a user.
"""
self.debug("start test")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_1"])
self.ldapconfRes=self._addLdapConfiguration(self.services["ldapConfiguration_1"])
if(self.ldapconfRes==1):
self.debug("Ldap Configuration was succcessful")
self.debug("configure ldap successful")
#validating the user credentials with ldap Server
loginRes = self.chkLogin(self.services["ldapCon_1"]["ldapusername"], self.services["ldapCon_1"]["ldappasswd"])
self.assertEquals(loginRes,1,"ldap Authentication failed")
loginRes = self._checkLogin(self.services["ldapConfiguration_1"]["ldapUsername"],self.services["ldapConfiguration_1"]["ldapPassword"])
self.debug(loginRes)
self.assertEquals(loginRes,1,"Ldap Authentication")
else:
self.debug("LDAP Configuration failed with exception")
self.assertEquals(self.ldapconfRes,1,"ldapConfig API failed")
self.assertEquals(self.ldapconfRes,1,"addLdapConfiguration failed")
self.debug("end test")
@attr(tags=["advanced", "basic"])
def test_02_configLDAP(self):
'''
This test is to verify ldapConfig API with valid values.(i.e query fileter as displayName)
'''
# 1. This test covers ldapConfig & login API with valid ldap credentials.
# 2. require ldap configuration:ldapCon_2
self.debug("start test")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_2"])
self.assertEquals(self.ldapconfRes,1,"ldapConfig API failed")
if(self.ldapconfRes==1):
self.debug("configure ldap successful")
#validating the user credentials with ldap Server
loginRes = self.chkLogin(self.services["ldapCon_2"]["ldapusername"], self.services["ldapCon_2"]["ldappasswd"])
self.assertEquals(loginRes,1,"ldap Authentication failed")
else:
self.debug("LDAP Configuration failed with exception")
self.debug("end test")
@attr(tags=["advanced", "basic"])
def test_03_configLDAP(self):
'''
This test is to verify ldapConfig API with missing config parameters value(i.queryfilter)
'''
# 1. Issue ldapConfig API with no ldap config parameter value and check behavior
# 2. require ldap configuration:ldapCon_3
self.debug("start test...")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_3"])
self.assertEquals(self.ldapconfRes,0,"LDAP configuration successful with invalid value.API failed")
self.debug("end test")
@attr(tags=["advanced", "basic"])
def test_04_configLDAP(self):
'''
This test is to verify ldapConfig API with invalid configuration values(by passing wrong query filter)
'''
# 1. calling ldapConfig API with invalid query filter value and check behavior
# 2. require ldap configuration:ldapCon_4
self.debug("start test...")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_4"])
self.assertEquals(self.ldapconfRes,0,"API failed")
@attr(tags=["advanced", "basic"])
def test_05_configLDAP(self):
'''
This test is to verify login API functionality by passing wrong ldap credentials
'''
# 1.This script first configure the ldap and validates the user credentials using login API
# 2. require ldap configuration:ldapCon_5
self.debug("start test")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_5"])
self.assertEquals(self.ldapconfRes,1,"API failed")
#validating the cloudstack user credentials with ldap Server
loginRes = self.chkLogin(self.services["ldapCon_5"]["ldapusername"], self.services["ldapCon_5"]["ldappasswd"])
self.assertNotEqual(loginRes,1,"login API failed")
self.debug("end test")
@attr(tags=["advanced", "basic"])
def test_06_removeLDAP(self):
'''
This test is to verify ldapRemove API functionality
'''
# 1. This script fist configures ldap and removes the configured ldap values
# 2. require ldap configuration:ldapCon_1
self.debug("start test")
self.ldapconfRes=self._testldapConfig(self.services["ldapCon_1"])
if(self.ldapconfRes==1):
self.debug("ldap configured successfully")
deleteldapconfg=ldapRemove.ldapRemoveCmd()
res=self.apiclient.ldapRemove(deleteldapconfg)
self.debug("ldap removed successfully")
self.ldapconfRes=0
else:
self.debug("LDAP Configuration failed with exception")
self.assertEquals(self.ldapconfRes,0,"ldapconfig API failed")
self.debug("end test")
def _testldapConfig(self,ldapSrvD):
def _addLdapConfiguration(self,ldapConfiguration):
"""
:param ldapSrvD
:param ldapConfiguration
"""
#This Method takes dictionary as parameter,
# reads the ldap configuration values from the passed dictionary and
# register the ldapconfig detail in cloudstack
# & return true or false based on ldapconfig API response
self.debug("start ldapconfig test")
#creating the ldapconfig cmd object
lpconfig = ldapConfig.ldapConfigCmd()
#Config the ldap server by assigning the ldapconfig dict variable values to ldapConfig object
lpconfig.hostname = ldapSrvD["ldapHostname"]
lpconfig.port = ldapSrvD["port"]
lpconfig.binddn = ldapSrvD["binddn"]
lpconfig.bindpass = ldapSrvD["bindpass"]
lpconfig.searchbase = ldapSrvD["searchbase"]
lpconfig.queryfilter = ldapSrvD["queryfilter"]
# Setup Global settings
#end of assigning the variables
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
updateConfigurationCmd.name = "ldap.basedn"
updateConfigurationCmd.value = ldapConfiguration['basedn']
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
#calling the ldapconfig Api
self.debug("calling ldapconfig API")
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
updateConfigurationCmd.name = "ldap.email.attribute"
updateConfigurationCmd.value = ldapConfiguration['emailAttribute']
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
updateConfigurationCmd.name = "ldap.realname.attribute"
updateConfigurationCmd.value = ldapConfiguration['realnameAttribute']
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
updateConfigurationCmd.name = "ldap.user.object"
updateConfigurationCmd.value = ldapConfiguration['userObject']
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
updateConfigurationCmd.name = "ldap.username.attribute"
updateConfigurationCmd.value = ldapConfiguration['usernameAttribute']
updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
self.debug("start addLdapConfiguration test")
ldapServer = addLdapConfiguration.addLdapConfigurationCmd()
ldapServer.hostname = ldapConfiguration['hostname']
ldapServer.port = ldapConfiguration['port']
self.debug("calling addLdapConfiguration API command")
try:
lpconfig1 = self.apiclient.ldapConfig(lpconfig)
self.debug("ldapconfig API succesfful")
self.apiClient.addLdapConfiguration(ldapServer)
self.debug("addLdapConfiguration was successful")
return 1
except Exception, e:
self.debug("ldapconfig API failed %s" %e)
self.debug("addLdapConfiguration failed %s" %e)
return 0
def chkLogin(self, username, password):
def _deleteLdapConfiguration(self,ldapConfiguration):
"""
:param ldapConfiguration
"""
ldapServer = deleteLdapConfiguration.deleteLdapConfigurationCmd()
ldapServer.hostname = ldapConfiguration["hostname"]
try:
self.apiClient.deleteLdapConfiguration(ldapServer)
self.debug("deleteLdapConfiguration was successful")
return 1
except Exception, e:
self.debug("deleteLdapConfiguration failed %s" %e)
return 0
def _checkLogin(self, username, password):
"""
:param username:
:param password:
"""
self.debug("login test")
self.debug("Attempting to login.")
try:
login1 = login.loginCmd()
login1.username = username
login1.password = password
loginRes = self.apiclient.login(login1)
loginParams = login.loginCmd()
loginParams.username = username
loginParams.password = password
loginRes = self.apiClient.login(loginParams)
self.debug("login response %s" % loginRes)
if loginRes is None:
self.debug("login not successful")
return 0
else:
self.debug("login successful")
return 1

View File

@ -118,7 +118,7 @@ known_categories = {
'TrafficType': 'Usage',
'Product': 'Product',
'LB': 'Load Balancer',
'ldap': 'LDAP',
'Ldap': 'LDAP',
'Swift': 'Swift',
'S3' : 'S3',
'SecondaryStorage': 'Host',

View File

@ -5830,7 +5830,7 @@ label.error {
.multi-wizard .buttons {
width: 100%;
position: absolute;
top: 519px;
bottom: 10px;
left: 0px;
}
@ -12267,3 +12267,98 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
color: #0000FF !important;
}
.accounts-wizard table {
margin: 0;
width: 100%;
table-layout: fixed;
}
.accounts-wizard .ui-button {
display: inline-block !important;
float: none !important;
}
.accounts-wizard td:last-child {
border: none;
}
.accounts-wizard tbody tr:nth-child(even) {
background: #DFE1E3;
}
.accounts-wizard tbody tr:nth-child(odd) {
background: #F2F0F0;
}
.accounts-wizard .content {
display: inline-block;
}
.accounts-wizard .content:last-child {
margin-left: 14px;
}
.accounts-wizard .input-area {
width: 320px;
font-size: 13px;
color: #485867;
text-shadow: 0px 2px 1px #FFFFFF;
}
.ldap-account-choice {
border: none !important;
border-radius: 0 0 0 0 !important;
}
.manual-account-details .name {
margin-top: 2px;
width: 100px;
float: left;
padding-bottom:10px;
}
.manual-account-details {
height: auto !important;
overflow: visible !important;
overflow-x: visible !important;
}
.manual-account-details label.error {
display: block;
font-size: 10px;
}
.manual-account-details .value {
float: left;
}
.manual-account-details .form-item:after {
content:".";
display: block;
clear: both;
visibility: hidden;
line-height: 0;
height: 0;
}
.manual-account-details .form-item {
padding: 5px;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.manual-account-details select, .manual-account-details input {
width: 150px;
}
.manual-account-details input {
background: #F6F6F6;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
border-radius: 4px 4px 4px 4px;
border: 1px solid #AFAFAF;
-moz-box-shadow: inset 0px 1px #727272;
-webkit-box-shadow: inset 0px 1px #727272;
-o-box-shadow: inset 0px 1px #727272;
box-shadow: inset 0px 1px #727272;
-moz-box-shadow: inset 0px 1px 0px #727272;
-webkit-box-shadow: inset 0px 1px 0px #727272;
-o-box-shadow: inset 0px 1px 0px #727272;
}
.manual-account-details > *:nth-child(even) {
background: #DFE1E3;
}
.manual-account-details > *:nth-child(odd) {
background: #F2F0F0;
}
.manual-account-details .value {
display: inline-block;
}

View File

@ -54,6 +54,7 @@ dictionary = {
'changed.item.properties': '<fmt:message key="changed.item.properties" />',
'confirm.enable.s3': '<fmt:message key="confirm.enable.s3" />',
'confirm.enable.swift': '<fmt:message key="confirm.enable.swift" />',
'error.could.not.change.your.password.because.ldap.is.enabled': '<fmt:message key="error.could.not.change.your.password.because.ldap.is.enabled" />',
'error.could.not.enable.zone': '<fmt:message key="error.could.not.enable.zone" />',
'error.installWizard.message': '<fmt:message key="error.installWizard.message" />',
'error.invalid.username.password': '<fmt:message key="error.invalid.username.password" />',
@ -526,7 +527,7 @@ dictionary = {
'label.edit.lb.rule': '<fmt:message key="label.edit.lb.rule" />',
'label.edit.network.details': '<fmt:message key="label.edit.network.details" />',
'label.edit.project.details': '<fmt:message key="label.edit.project.details" />',
'label.edit.tags': '<fmt:message key="label.edit.tags" />',
'label.edit.tags': '<fmt:message key="label.edit.tags" />',
'label.edit.traffic.type': '<fmt:message key="label.edit.traffic.type" />',
'label.edit.vpc': '<fmt:message key="label.edit.vpc" />',
'label.egress.rule': '<fmt:message key="label.egress.rule" />',

View File

@ -238,10 +238,10 @@ under the License.
<!-- Step 6: Network -->
<div class="step network always-load" wizard-step-id="network">
<!-- 5a: Network description -->
<div class="wizard-step-conditional nothing-to-select">
<div class="wizard-step-conditional nothing-to-select">
<p id="from_instance_page_1"><fmt:message key="message.zone.no.network.selection"/></p>
<p id="from_instance_page_2"><fmt:message key="message.please.proceed"/></p>
<p id="from_vpc_tier"></p>
<p id="from_vpc_tier"></p>
</div>
<!-- 5b: Select network -->
@ -446,7 +446,7 @@ under the License.
<a href="6"><fmt:message key="label.edit"/></a>
</div>
</div>
<!-- Security groups -->
<div class="select odd">
<div class="name">
@ -483,6 +483,37 @@ under the License.
<div class="button next"><span><fmt:message key="label.next"/></span></div>
</div>
</div>
<!-- Accounts wizard -->
<div class="multi-wizard accounts-wizard">
<form>
<div class="steps">
<div class="content ldap-account-choice">
<div class="select-container">
<table>
<thead>
<tr>
<th style="width:40px">Select</th>
<th style="width:110px">Realname</th>
<th style="width:70px">Username</th>
<th>Email</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="content input-area">
<div class="select-container manual-account-details">
</div>
</div>
</div>
</form>
<div class="buttons">
<button class="cancel ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span><fmt:message key="label.cancel"/></span></button>
<button class="next ok ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span><fmt:message key="label.add"/></span></button>
</div>
</div>
<!-- Zone wizard -->
<div class="multi-wizard zone-wizard">
<div class="progress">
@ -519,7 +550,7 @@ under the License.
</div>
<div class="select-area advanced-zone disabled">
<div class="desc">
<fmt:message key="message.desc.advanced.zone"/>
<fmt:message key="message.desc.advanced.zone"/>
</div>
<input type="radio" name="network-model" value="Advanced" />
<label><fmt:message key="label.advanced"/></label>
@ -547,7 +578,7 @@ under the License.
<div class="setup-zone" zone-wizard-form="zone"
zone-wizard-step-id="addZone">
<div class="info-desc">
<fmt:message key="message.desc.zone"/>
<fmt:message key="message.desc.zone"/>
</div>
<div class="content input-area">
<div class="select-container"></div>
@ -766,7 +797,7 @@ under the License.
<li class="secondary-storage"><fmt:message key="label.secondary.storage"/></li>
</ul>
<div class="info-desc">
<fmt:message key="message.desc.host"/>
<fmt:message key="message.desc.host"/>
</div>
<div class="content input-area">
<div class="select-container"></div>
@ -990,7 +1021,7 @@ under the License.
<span><fmt:message key="label.refresh"/></span>
</div>
<div id="update_ssl_button" class="button action main-action reduced-hide lock" title="Updates your Console Proxy SSL Certificate">
<span class="icon">&nbsp;</span>
<span class="icon">&nbsp;</span>
<span><fmt:message key="label.update.ssl.cert"/></span>
</div>
</div>
@ -1064,7 +1095,7 @@ under the License.
<span class="button view-all hosts"
view-all-title="<fmt:message key="label.virtual.routers"/>"
view-all-target="virtualRouters"><fmt:message key="label.view.all"/></span>
</li>
</li>
</ul>
</div>
</div>
@ -1239,7 +1270,7 @@ under the License.
<div class="title">
<span></span>
</div>
<div class="button fetch-latest">
<span><fmt:message key="label.fetch.latest"/></span>
</div>
@ -1632,7 +1663,7 @@ under the License.
<script src="lib/jquery.js" type="text/javascript"></script>
<script src="lib/jquery.easing.js" type="text/javascript"></script>
<script src="lib/jquery.validate.js" type="text/javascript"></script>
<script src="lib/jquery-ui/js/jquery-ui.js" type="text/javascript"></script>
<script src="lib/jquery-ui/js/jquery-ui.js" type="text/javascript"></script>
<script src="lib/date.js" type="text/javascript"></script>
<script src="lib/jquery.cookies.js" type="text/javascript"></script>
<script src="lib/jquery.md5.js" type="text/javascript" ></script>
@ -1656,7 +1687,7 @@ under the License.
<script type="text/javascript" src="scripts/ui/utils.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/events.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/dialog.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/multiEdit.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/overlay.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/dataTable.js?t=<%=now%>"></script>
@ -1664,7 +1695,7 @@ under the License.
<script type="text/javascript" src="scripts/ui/widgets/listView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/detailView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/treeView.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/notifications.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/notifications.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/tagger.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui/widgets/toolTip.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/cloud.core.callbacks.js?t=<%=now%>"></script>
@ -1685,8 +1716,8 @@ under the License.
<script type="text/javascript" src="scripts/dashboard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/instanceWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/instanceWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/affinity.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/instances.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/events.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/regions.js?t=<%=now%>"></script>
@ -1701,6 +1732,8 @@ under the License.
<script type="text/javascript" src="scripts/ui-custom/uploadVolume.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/storage.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/templates.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/accountsWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/ui-custom/accountsWizard.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/accounts.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/configuration.js?t=<%=now%>"></script>
<script type="text/javascript" src="scripts/globalSettings.js?t=<%=now%>"></script>

View File

@ -76,222 +76,20 @@
return 'label.add.account';
}
},
createForm: {
title: 'label.add.account',
desc: 'label.add.account',
fields: {
username: {
label: 'label.username',
validation: {
required: true
},
docID: 'helpAccountUsername'
},
password: {
label: 'label.password',
validation: {
required: true
},
isPassword: true,
id: 'password',
docID: 'helpAccountPassword'
},
'password-confirm': {
label: 'label.confirm.password',
validation: {
required: true,
equalTo: '#password'
},
isPassword: true,
docID: 'helpAccountConfirmPassword'
},
email: {
label: 'label.email',
validation: {
required: true,
email: true
},
docID: 'helpAccountEmail'
},
firstname: {
label: 'label.first.name',
validation: {
required: true
},
docID: 'helpAccountFirstName'
},
lastname: {
label: 'label.last.name',
validation: {
required: true
},
docID: 'helpAccountLastName'
},
domainid: {
label: 'label.domain',
docID: 'helpAccountDomain',
validation: {
required: true
},
select: function(args) {
var data = {};
if (args.context.users) { // In accounts section
data.listAll = true;
} else if (args.context.domains) { // In domain section (use specific domain)
data.id = args.context.domains[0].id;
}
$.ajax({
url: createURL("listDomains"),
data: data,
dataType: "json",
async: false,
success: function(json) {
var items = [];
domainObjs = json.listdomainsresponse.domain;
$(domainObjs).each(function() {
items.push({
id: this.id,
description: this.path
});
if (this.level == 0)
rootDomainId = this.id;
});
args.response.success({
data: items
});
}
});
}
},
account: {
label: 'label.account',
docID: 'helpAccountAccount'
},
accounttype: {
label: 'label.type',
docID: 'helpAccountType',
validation: {
required: true
},
select: function(args) {
var items = [];
items.push({
id: 0,
description: "User"
}); //regular-user
items.push({
id: 1,
description: "Admin"
}); //root-admin
args.response.success({
data: items
});
}
},
timezone: {
label: 'label.timezone',
docID: 'helpAccountTimezone',
select: function(args) {
var items = [];
items.push({
id: "",
description: ""
});
for (var p in timezoneMap)
items.push({
id: p,
description: timezoneMap[p]
});
args.response.success({
data: items
});
}
},
networkdomain: {
label: 'label.network.domain',
docID: 'helpAccountNetworkDomain',
validation: {
required: false
}
}
}
},
action: function(args) {
var data = {
username: args.data.username,
};
var password = args.data.password;
if (md5Hashed) {
password = $.md5(password);
}
$.extend(data, {
password: password
});
$.extend(data, {
email: args.data.email,
firstname: args.data.firstname,
lastname: args.data.lastname,
domainid: args.data.domainid
});
var account = args.data.account;
if (account == null || account.length == 0) {
account = args.data.username;
}
$.extend(data, {
account: account
});
var accountType = args.data.accounttype;
if (args.data.accounttype == "1" && args.data.domainid != rootDomainId) { //if account type is admin, but domain is not Root domain
accountType = "2"; // Change accounttype from root-domain("1") to domain-admin("2")
}
$.extend(data, {
accounttype: accountType
});
if (args.data.timezone != null && args.data.timezone.length > 0) {
$.extend(data, {
timezone: args.data.timezone
});
}
if (args.data.networkdomain != null && args.data.networkdomain.length > 0) {
$.extend(data, {
networkdomain: args.data.networkdomain
});
}
$.ajax({
url: createURL('createAccount'),
type: "POST",
data: data,
success: function(json) {
var item = json.createaccountresponse.account;
args.response.success({
data: item
});
},
error: function(XMLHttpResponse) {
args.response.error(parseXMLHttpResponse(XMLHttpResponse));
}
});
},
notification: {
poll: function(args) {
args.complete({
actionFilter: accountActionfilter
});
}
}
},
action: {
custom: cloudStack.uiCustom.accountsWizard(
cloudStack.accountsWizard
)
},
}
},
@ -1254,47 +1052,56 @@
return 'label.action.change.password';
}
},
createForm: {
title: 'label.action.change.password',
fields: {
newPassword: {
label: 'label.new.password',
isPassword: true,
validation: {
required: true
},
id: 'newPassword'
},
'password-confirm': {
label: 'label.confirm.password',
validation: {
required: true,
equalTo: '#newPassword'
},
isPassword: true
}
}
},
action: function(args) {
var password = args.data.newPassword;
if (md5Hashed)
password = $.md5(password);
var data = {
id: args.context.users[0].id,
password: password
};
action: function(args) {
if (isLdapEnabled()) {
alert(dictionary["error.could.not.change.your.password.because.ldap.is.enabled"]);
args.response.error({});
} else {
cloudStack.dialog.createForm({
noDialog: false,
form: {
title: 'label.action.change.password',
fields: {
newPassword: {
label: 'label.new.password',
isPassword: true,
validation: {
required: true
},
id: 'newPassword'
},
'password-confirm': {
label: 'label.confirm.password',
validation: {
required: true,
equalTo: '#newPassword'
},
isPassword: true
}
}
}
})
var password = args.data.newPassword;
if (md5Hashed)
password = $.md5(password);
$.ajax({
url: createURL('updateUser'),
data: data,
type: "POST",
success: function(json) {
args.response.success({
data: json.updateuserresponse.user
});
}
});
var data = {
id: args.context.users[0].id,
password: password
};
$.ajax({
url: createURL('updateUser'),
data: data,
type: "POST",
success: function(json) {
args.response.success({
data: json.updateuserresponse.user
});
}
});
}
},
notification: {
poll: function(args) {

View File

@ -0,0 +1,288 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
(function(cloudStack, $) {
cloudStack.accountsWizard = {
informationWithinLdap: {
username: {
label: 'label.username',
validation: {
required: true
},
docID: 'helpAccountUsername'
},
password: {
label: 'label.password',
validation: {
required: true
},
isPassword: true,
id: 'password',
docID: 'helpAccountPassword'
},
'password-confirm': {
label: 'label.confirm.password',
validation: {
required: true,
equalTo: '#password'
},
isPassword: true,
docID: 'helpAccountConfirmPassword'
},
email: {
label: 'label.email',
validation: {
required: true,
email: true
},
docID: 'helpAccountEmail'
},
firstname: {
label: 'label.first.name',
validation: {
required: true
},
docID: 'helpAccountFirstName'
},
lastname: {
label: 'label.last.name',
validation: {
required: true
},
docID: 'helpAccountLastName'
}
},
informationNotInLdap: {
domainid: {
label: 'label.domain',
docID: 'helpAccountDomain',
validation: {
required: true
},
select: function(args) {
var data = {};
if (args.context.users) { // In accounts section
data.listAll = true;
} else if (args.context.domains) { // In domain section (use specific domain)
data.id = args.context.domains[0].id;
}
$.ajax({
url: createURL("listDomains"),
data: data,
dataType: "json",
async: false,
success: function(json) {
var items = [];
domainObjs = json.listdomainsresponse.domain;
$(domainObjs).each(function() {
items.push({
id: this.id,
description: this.path
});
if (this.level === 0)
rootDomainId = this.id;
});
args.response.success({
data: items
});
}
});
}
},
account: {
label: 'label.account',
docID: 'helpAccountAccount',
validation: {
required: false
}
},
accounttype: {
label: 'label.type',
docID: 'helpAccountType',
validation: {
required: true
},
select: function(args) {
var items = [];
items.push({
id: 0,
description: "User"
}); //regular-user
items.push({
id: 1,
description: "Admin"
}); //root-admin
args.response.success({
data: items
});
}
},
timezone: {
label: 'label.timezone',
docID: 'helpAccountTimezone',
select: function(args) {
var items = [];
items.push({
id: "",
description: ""
});
for (var p in timezoneMap)
items.push({
id: p,
description: timezoneMap[p]
});
args.response.success({
data: items
});
}
},
networkdomain: {
label: 'label.network.domain',
docID: 'helpAccountNetworkDomain',
validation: {
required: false
}
}
},
action: function(args) {
var array1 = [];
var ldapStatus = isLdapEnabled();
console.log("creating user: " + args.username);
array1.push("&username=" + args.username);
if (!ldapStatus) {
var password = args.data.password;
if (md5Hashed) {
password = $.md5(password);
}
array1.push("&email=" + args.data.email);
array1.push("&firstname=" + args.data.firstname);
array1.push("&lastname=" + args.data.lastname);
var password = args.data.password;
if (md5Hashed) {
password = $.md5(password);
}
array1.push("&password=" + password);
}
array1.push("&domainid=" + args.data.domainid);
var account = args.data.account;
if (account === null || account.length === 0) {
account = args.username;
}
array1.push("&account=" + account);
var accountType = args.data.accounttype;
if (args.data.accounttype == "1" && args.data.domainid != rootDomainId) { //if account type is admin, but domain is not Root domain
accountType = "2"; // Change accounttype from root-domain("1") to domain-admin("2")
}
array1.push("&accounttype=" + accountType);
if (args.data.timezone !== null && args.data.timezone.length > 0) {
array1.push("&timezone=" + args.data.timezone);
}
if (args.data.networkdomain !== null && args.data.networkdomain.length > 0) {
array1.push("&networkdomain=" + args.data.networkdomain);
}
if (ldapStatus) {
console.log("doing an ldap add");
$.ajax({
url: createURL('ldapCreateAccount' + array1.join("")),
dataType: "json",
async: false,
success: function(json) {
var item = json.createaccountresponse.account;
args.response.success({
data: item
});
},
error: function(XMLHttpResponse) {
args.response.error(parseXMLHttpResponse(XMLHttpResponse));
}
});
} else {
console.log("doing normal user add");
$.ajax({
url: createURL('createAccount' + array1.join("")),
dataType: "json",
async: false,
success: function(json) {
var item = json.createaccountresponse.account;
args.response.success({
data: item
});
},
error: function(XMLHttpResponse) {
args.response.error(parseXMLHttpResponse(XMLHttpResponse));
}
});
}
}
/*
action: function(args) {
var array1 = [];
var username = args.data.username;
array1.push("&domainid=" + args.data.domainid);
if (args.data.account != null && args.data.account.length != 0) {
array1.push("&account=" + args.data.account);
}
if (args.data.accounttype == "1" && args.data.domainid != rootDomainId) {
args.data.accounttype = "2";
}
array1.push("&accountType=" + args.data.accounttype);
if (args.data.timezone != null && args.data.timezone.length != 0) {
array1.push("&timezone=" + args.data.timezone);
}
if (args.data.networkdomain != null && args.data.networkdomain != 0) {
array1.push("&networkDomain=" + args.data.networkdomain);
}
for (var i = 0; i < username.length; i++) {
$.ajax({
url: createURL("ldapCreateAccount&username=" + username[i] + array1.join("")),
dataType: "json",
async: false,
success: function(json) {
var item = json.createaccountresponse.account;
args.response.success({
data: item
});
},
error: function(XMLHttpResponse) {
args.response.error(parseXMLHttpResponse(XMLHttpResponse));
}
});
}
}
*/
};
}(cloudStack, jQuery));

View File

@ -99,7 +99,6 @@
}
}
},
ldapConfiguration: {
type: 'select',
title: 'LDAP Configuration',
@ -110,29 +109,18 @@
hostname: {
label: 'Hostname'
},
queryfilter: {
label: 'Query Filter'
},
searchbase: {
label: 'Search Base'
},
port: {
label: 'LDAP Port'
},
ssl: {
label: 'SSL'
}
},
dataProvider: function(args) {
var data = {};
listViewDataProvider(args, data);
$.ajax({
url: createURL('ldapConfig&listall=true'), //Need a list LDAP configuration API call which needs to be implemented
url: createURL('listLdapConfigurations'),
data: data,
success: function(json) {
var items = json.ldapconfigresponse.ldapconfig;
var items = json.ldapconfigurationresponse.LdapConfiguration;
args.response.success({
data: items
});
@ -142,12 +130,9 @@
}
});
},
detailView: {
name: 'label.details',
actions: {
// Remove LDAP
remove: {
label: 'Remove LDAP',
messages: {
@ -159,192 +144,96 @@
}
},
action: function(args) {
$.ajax({
url: createURL("ldapRemove"),
url: createURL("deleteLdapConfiguration&hostname=" + args.context.ldapConfiguration[0].hostname),
success: function(json) {
args.response.success();
}
});
$(window).trigger('cloudStack.fullRefresh');
}
}
},
tabs: {
details: {
title: 'LDAP Configuration Details',
fields: [{
hostname: {
label: 'Hostname'
},
description: {
label: 'label.description'
},
ssl: {
label: 'SSL'
port: {
label: 'Port'
}
}],
dataProvider: function(args) {
var items = [];
console.log(args);
$.ajax({
url: createURL("ldapConfig&listAll=true"),
url: createURL("listLdapConfigurations&hostname=" + args.context.ldapConfiguration[0].hostname),
dataType: "json",
async: true,
success: function(json) {
var item = json.ldapconfigresponse.ldapconfig;
var item = json.ldapconfigurationresponse.LdapConfiguration;
args.response.success({
data: item
data: item[0]
});
}
});
}
}
}
},
actions: {
add: {
label: 'Configure LDAP',
messages: {
confirm: function(args) {
return 'Do you really want to configure LDAP ? ';
},
notification: function(args) {
return 'LDAP configured';
console.log(args);
return 'Successfully added a new LDAP server';
}
},
createForm: {
title: 'Configure LDAP',
fields: {
name: {
label: 'Bind DN',
validation: {
required: true
}
},
password: {
label: 'Bind Password',
validation: {
required: true
},
isPassword: true
},
hostname: {
label: 'Hostname',
validation: {
required: true
}
},
queryfilter: {
label: 'Query Filter',
validation: {
required: true
},
docID: 'helpLdapQueryFilter'
},
searchbase: {
label: 'SearchBase',
validation: {
required: true
}
},
ssl: {
label: 'SSL',
isBoolean: true,
isChecked: false
},
port: {
label: 'Port',
defaultValue: '389'
},
truststore: {
label: 'Trust Store',
isHidden: true,
dependsOn: 'ssl',
validation: {
required: true
}
},
truststorepassword: {
label: 'Trust Store Password',
isHidden: true,
dependsOn: 'ssl',
validation: {
required: true
}
}
}
},
action: function(args) {
var array = [];
array.push("&binddn=" + todb(args.data.name));
array.push("&bindpass=" + todb(args.data.password));
array.push("&hostname=" + todb(args.data.hostname));
array.push("&searchbase=" + todb(args.data.searchbase));
array.push("&queryfilter=" + todb(args.data.queryfilter));
array.push("&port=" + todb(args.data.port));
if (args.$form.find('.form-item[rel=ssl]').find('input[type=checkbox]').is(':Checked') == true) {
array.push("&ssl=true");
if (args.data.truststore != "")
array.push("&truststore=" + todb(args.data.truststore));
if (args.data.truststorepassword != "")
array.push("&truststorepass=" + todb(args.data.truststorepassword));
} else
array.push("&ssl=false");
array.push("&port=" + todb(args.data.port));;
$.ajax({
url: createURL("ldapConfig" + array.join("")),
url: createURL("addLdapConfiguration" + array.join("")),
dataType: "json",
type: "POST",
async: true,
success: function(json) {
var items = json.ldapconfigresponse.ldapconfig;
var items = json.ldapconfigurationresponse.LdapAddConfiguration;
args.response.success({
data: items
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
}
}
}
}
},
hypervisorCapabilities: {
type: 'select',
@ -440,4 +329,4 @@
}
}
};
})(cloudStack);
})(cloudStack);

View File

@ -699,7 +699,23 @@ var addGuestNetworkDialog = {
}
// Role Functions
function isLdapEnabled() {
var result;
$.ajax({
url: createURL("listLdapConfigurations"),
dataType: "json",
async: false,
success: function(json) {
result = (json.ldapconfigurationresponse.count > 0);
},
error: function(json) {
result = false;
}
});
return result;
}
// Role Functions
function isAdmin() {
return (g_role == 1);

View File

@ -0,0 +1,169 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
(function($, cloudStack) {
cloudStack.uiCustom.accountsWizard = function(args) {
return function(listViewArgs) {
var context = listViewArgs.context;
var ldapStatus = isLdapEnabled();
var accountsWizard = function(data) {
var $wizard = $('#template').find('div.accounts-wizard').clone();
var $form = $wizard.find('form');
var close = function() {
$wizard.dialog('destroy');
$('div.overlay').fadeOut(function() {
$('div.overlay').remove();
});
};
var completeAction = function() {
var data = cloudStack.serializeForm($form);
var username = data.username;
var bulkAdd = (username instanceof Array);
if (bulkAdd) {
console.log("doing bulk add");
for (var i = 0; i < username.length; i++) {
console.log("creating user " + username[i]);
args.action({
context: context,
data: data,
username: username[i],
response: {
error: function(message) {
if (message) {
cloudStack.dialog.notice({
message: message
});
}
}
}
});
}
} else {
args.action({
context: context,
data: data,
username: username,
response: {
error: function(message) {
if (message) {
cloudStack.dialog.notice({
message: message
});
}
}
}
});
}
};
$wizard.click(function(event) {
var $target = $(event.target);
if ($target.closest('button.next').size()) {
$form.validate();
if ($form.valid()) {
completeAction();
$(window).trigger('cloudStack.fullRefresh');
close();
return true;
}
}
if ($target.closest('button.cancel').size()) {
close();
return false;
}
});
if (ldapStatus) {
var $table = $wizard.find('.ldap-account-choice tbody');
$.ajax({
url: createURL("listLdapUsers&listtype=new"),
dataType: "json",
async: false,
success: function(json) {
if (json.ldapuserresponse.count > 0) {
$(json.ldapuserresponse.LdapUser).each(function() {
var result = $("<tr>");
result.append("<td><input type=\"checkbox\" class=\"required\" name=\"username\" value=\"" + this.username + "\"></td>");
result.append("<td>" + this.firstname + " " + this.lastname + "</td>");
result.append("<td>" + this.username + "</td>");
result.append("<td>" + this.email + "</td>");
$table.append(result);
});
} else {
var result = $("<tr>");
result.append("<td colspan=\"4\">No data to show</td>");
$table.append(result);
}
}
});
} else {
var informationWithinLdap = cloudStack.dialog.createForm({
context: context,
noDialog: true,
form: {
title: '',
fields: args.informationWithinLdap
}
});
//console.log(informationWithinLdap.$formContainer);
var informationWithinLdapForm = informationWithinLdap.$formContainer.find('form .form-item');
informationWithinLdapForm.find('.value #label_username').addClass('required');
informationWithinLdapForm.find('.value #password').addClass('required');
informationWithinLdapForm.find('.value #label_confirm_password').addClass('required');
informationWithinLdapForm.find('.value #label_confirm_password').attr('equalTo', '#password');
informationWithinLdapForm.find('.value #label_email').addClass('required');
informationWithinLdapForm.find('.value #label_first_name').addClass('required');
informationWithinLdapForm.find('.value #label_last_name').addClass('required');
$wizard.find('.manual-account-details').append(informationWithinLdapForm).children().css('background', 'none');
$wizard.find('.ldap-account-choice').css('display', 'none');
$wizard.removeClass('multi-wizard');
}
var informationNotInLdap = cloudStack.dialog.createForm({
context: context,
noDialog: true,
form: {
title: '',
fields: args.informationNotInLdap
}
});
var informationNotInLdapForm = informationNotInLdap.$formContainer.find('form .form-item');
informationNotInLdapForm.find('.value #label_domain').addClass('required');
informationNotInLdapForm.find('.value #label_type').addClass('required');
if (!ldapStatus) {
informationNotInLdapForm.css('background', 'none');
}
$wizard.find('.manual-account-details').append(informationNotInLdapForm);
return $wizard.dialog({
title: _l('label.add.account'),
width: ldapStatus ? 800 : 330,
height: ldapStatus ? 500 : 500,
closeOnEscape: false,
zIndex: 5000
}).closest('.ui-dialog').overlay();
};
accountsWizard(args);
};
};
})(jQuery, cloudStack);