mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Merge pull request #755 from karuturi/CLOUDSTACK-8647-2
Cloudstack:8647 LDAP Trust AD and AutoimportToday, CloudStack can automatically import LDAP users based on the configuration to a domain or an account. However, any new users in LDAP aren't automatically reflected. The admin has to manually import them again. This feature enables admin to map LDAP group/OU to a CloudStack domain and any changes are reflected in ACS as well. FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/WIP%3A+LDAP%3A+Trust+AD+and+Auto+Import testcases output: ``` ------------------------------------------------------- T E S T S ------------------------------------------------------- Running groovy.org.apache.cloudstack.ldap.NoLdapUserMatchingQueryExceptionSpec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.216 sec - in groovy.org.apache.cloudstack.ldap.NoLdapUserMatchingQueryExceptionSpec Running groovy.org.apache.cloudstack.ldap.LdapManagerImplSpec log4j:WARN No appenders could be found for logger (org.apache.cloudstack.ldap.LdapManagerImpl). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. using type: using type: null using type: TEST using type: TEST TEST using name: using name: null using accountType: -1 using accountType: 1 using accountType: 3 using accountType: 4 using accountType: 5 using accountType: 6 using accountType: 20000 using accountType: -500000 Tests run: 29, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.387 sec - in groovy.org.apache.cloudstack.ldap.LdapManagerImplSpec Running groovy.org.apache.cloudstack.ldap.LdapListUsersCmdSpec Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.041 sec - in groovy.org.apache.cloudstack.ldap.LdapListUsersCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapAddConfigurationCmdSpec Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.019 sec - in groovy.org.apache.cloudstack.ldap.LdapAddConfigurationCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapUserSpec Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.021 sec - in groovy.org.apache.cloudstack.ldap.LdapUserSpec Running groovy.org.apache.cloudstack.ldap.LdapAuthenticatorSpec Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.082 sec - in groovy.org.apache.cloudstack.ldap.LdapAuthenticatorSpec Running groovy.org.apache.cloudstack.ldap.LdapConfigurationVOSpec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 sec - in groovy.org.apache.cloudstack.ldap.LdapConfigurationVOSpec Running groovy.org.apache.cloudstack.ldap.OpenLdapUserManagerSpec Tests run: 12, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.094 sec - in groovy.org.apache.cloudstack.ldap.OpenLdapUserManagerSpec Running groovy.org.apache.cloudstack.ldap.LdapDeleteConfigurationCmdSpec Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.008 sec - in groovy.org.apache.cloudstack.ldap.LdapDeleteConfigurationCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapUserResponseSpec Tests run: 7, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.01 sec - in groovy.org.apache.cloudstack.ldap.LdapUserResponseSpec Running groovy.org.apache.cloudstack.ldap.LdapUserManagerFactorySpec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.027 sec - in groovy.org.apache.cloudstack.ldap.LdapUserManagerFactorySpec Running groovy.org.apache.cloudstack.ldap.ADLdapUserManagerImplSpec Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.012 sec - in groovy.org.apache.cloudstack.ldap.ADLdapUserManagerImplSpec Running groovy.org.apache.cloudstack.ldap.LdapCreateAccountCmdSpec Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.168 sec - in groovy.org.apache.cloudstack.ldap.LdapCreateAccountCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapImportUsersCmdSpec Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.063 sec - in groovy.org.apache.cloudstack.ldap.LdapImportUsersCmdSpec Running groovy.org.apache.cloudstack.ldap.LinkDomainToLdapCmdSpec Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.019 sec - in groovy.org.apache.cloudstack.ldap.LinkDomainToLdapCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapSearchUserCmdSpec Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.011 sec - in groovy.org.apache.cloudstack.ldap.LdapSearchUserCmdSpec Running groovy.org.apache.cloudstack.ldap.LdapListConfigurationCmdSpec Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.01 sec - in groovy.org.apache.cloudstack.ldap.LdapListConfigurationCmdSpec Running groovy.org.apache.cloudstack.ldap.NoSuchLdapUserExceptionSpec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.005 sec - in groovy.org.apache.cloudstack.ldap.NoSuchLdapUserExceptionSpec Running groovy.org.apache.cloudstack.ldap.LdapConfigurationResponseSpec Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 sec - in groovy.org.apache.cloudstack.ldap.LdapConfigurationResponseSpec Running groovy.org.apache.cloudstack.ldap.LdapConfigurationSpec asserting for provider configuration: openldap asserting for provider configuration: microsoftad asserting for provider configuration: asserting for provider configuration: asserting for provider configuration: xyz asserting for provider configuration: MicrosoftAd asserting for provider configuration: OpenLdap asserting for provider configuration: MicrosoftAD Tests run: 19, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.053 sec - in groovy.org.apache.cloudstack.ldap.LdapConfigurationSpec Running groovy.org.apache.cloudstack.ldap.LdapContextFactorySpec Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.099 sec - in groovy.org.apache.cloudstack.ldap.LdapContextFactorySpec Running groovy.org.apache.cloudstack.ldap.LdapConfigurationDaoImplSpec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.027 sec - in groovy.org.apache.cloudstack.ldap.LdapConfigurationDaoImplSpec Running groovy.org.apache.cloudstack.ldap.LdapUtilsSpec Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.01 sec - in groovy.org.apache.cloudstack.ldap.LdapUtilsSpec Results : Tests run: 156, Failures: 0, Errors: 0, Skipped: 0 ``` * pr/755: CLOUDSTACK-8647: linkdomaintoldap shouldnt fail when createuseraccount fails CLOUDSTACK-8647 removed duplicate key in create sql of ldap_trust_map CLOUDSTACK-8647: string formatting CLOUDSTACK-8647: updated with review comments CLOUDSTACK-8647: unittests for LdapAuthenticatorSpec CLOUDSTACK-8647: formatted LdapAuthenticatorSpec CLOUDSTACK-8647: UI for trust AD feature CLOUDSTACK-8647 added unittests for new methods in ldapmanager CLOUDSTACK-8647 unittests for LinkDomainToLdap api command CLOUDSTACK-8647: fixed unittests CLOUDSTACK-8647 support for assigning and admin to linked ldap domain CLOUDSTACK-8647 added nested group enabled config in ldap CLOUDSTACK-8647 added account_type to the linkDomainToLdap API CLOUDSTACK-8647 changed the authentication flow CLOUDSTACK-8647 added new api linkLdapToDomain CLOUDSTACK-8647: added cmd and response class for the new api Signed-off-by: Rajani Karuturi <rajani.karuturi@citrix.com>
This commit is contained in:
		
						commit
						5881035e7b
					
				| @ -628,6 +628,8 @@ public class ApiConstants { | ||||
|     public static final String OVM3_CLUSTER = "ovm3cluster"; | ||||
|     public static final String OVM3_VIP = "ovm3vip"; | ||||
| 
 | ||||
|     public static final String ADMIN = "admin"; | ||||
| 
 | ||||
|     public enum HostDetails { | ||||
|         all, capacity, events, stats, min; | ||||
|     } | ||||
|  | ||||
| @ -2133,6 +2133,10 @@ label.every=Every | ||||
| label.day=Day | ||||
| label.of.month=of month | ||||
| label.add.private.gateway=Add Private Gateway | ||||
| label.link.domain.to.ldap=Link Domain to LDAP | ||||
| message.link.domain.to.ldap=Enable autosync for this domain in LDAP | ||||
| label.ldap.link.type=Type | ||||
| label.account.type=Account Type | ||||
| message.desc.created.ssh.key.pair=Created a SSH Key Pair. | ||||
| message.please.confirm.remove.ssh.key.pair=Please confirm that you want to remove this SSH Key Pair | ||||
| message.password.has.been.reset.to=Password has been reset to | ||||
|  | ||||
| @ -771,6 +771,7 @@ deleteLdapConfiguration=3 | ||||
| listLdapUsers=3 | ||||
| ldapCreateAccount=3 | ||||
| importLdapUsers=3 | ||||
| linkDomainToLdap=3 | ||||
| 
 | ||||
| 
 | ||||
| #### juniper-contrail commands | ||||
|  | ||||
| @ -35,5 +35,6 @@ | ||||
|     <bean id="LdapConfigurationDao" | ||||
|         class="org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl" /> | ||||
|     <bean id="LdapConfiguration" class="org.apache.cloudstack.ldap.LdapConfiguration" /> | ||||
|     <bean id="LdapTrustMapDao" class="org.apache.cloudstack.ldap.dao.LdapTrustMapDaoImpl" /> | ||||
| 
 | ||||
| </beans> | ||||
|  | ||||
| @ -0,0 +1,115 @@ | ||||
| /* | ||||
|  * 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 com.cloud.exception.InvalidParameterValueException; | ||||
| import com.cloud.user.User; | ||||
| import com.cloud.user.UserAccount; | ||||
| 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.DomainResponse; | ||||
| import org.apache.cloudstack.api.response.LinkDomainToLdapResponse; | ||||
| 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; | ||||
| 
 | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| @APICommand(name = "linkDomainToLdap", description = "link an existing cloudstack domain to group or OU in ldap", responseObject = LinkDomainToLdapResponse.class, since = "4.6.0", | ||||
|     requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) | ||||
| public class LinkDomainToLdapCmd extends BaseCmd { | ||||
|     public static final Logger s_logger = Logger.getLogger(LinkDomainToLdapCmd.class.getName()); | ||||
|     private static final String s_name = "linkdomaintoldapresponse"; | ||||
| 
 | ||||
|     @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "The id of the domain which has to be " | ||||
|             + "linked to LDAP.") | ||||
|     private Long domainId; | ||||
| 
 | ||||
|     @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the ldap name. GROUP or OU") | ||||
|     private String type; | ||||
| 
 | ||||
|     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the group or OU in LDAP") | ||||
|     private String name; | ||||
| 
 | ||||
|     @Parameter(name = ApiConstants.ADMIN, type = CommandType.STRING, required = false, description = "domain admin username in LDAP ") | ||||
|     private String admin; | ||||
| 
 | ||||
|     @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, required = true, description = "Type of the account to auto import. Specify 0 for user and 2 for " + | ||||
|         "domain admin") | ||||
|     private short accountType; | ||||
| 
 | ||||
|     @Inject | ||||
|     private LdapManager _ldapManager; | ||||
| 
 | ||||
|     @Override | ||||
|     public void execute() throws ServerApiException { | ||||
|         try { | ||||
|             LinkDomainToLdapResponse response = _ldapManager.linkDomainToLdap(domainId, type, name, accountType); | ||||
|             if(admin!=null) { | ||||
|                 LdapUser ldapUser = null; | ||||
|                 try { | ||||
|                     ldapUser = _ldapManager.getUser(admin, type, name); | ||||
|                 } catch (NoLdapUserMatchingQueryException e) { | ||||
|                     s_logger.debug("no ldap user matching username " + admin + " in the given group/ou", e); | ||||
|                 } | ||||
|                 if (ldapUser != null && !ldapUser.isDisabled()) { | ||||
|                     Account account = _accountService.getActiveAccountByName(admin, domainId); | ||||
|                     if (account == null) { | ||||
|                         try { | ||||
|                             UserAccount userAccount = _accountService.createUserAccount(admin, "", ldapUser.getFirstname(), ldapUser.getLastname(), ldapUser.getEmail(), null, | ||||
|                                     admin, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, domainId, admin, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); | ||||
|                             response.setAdminId(String.valueOf(userAccount.getAccountId())); | ||||
|                             s_logger.info("created an account with name " + admin + " in the given domain " + domainId); | ||||
|                         } catch (Exception e) { | ||||
|                             s_logger.info("an exception occurred while creating account with name " + admin +" in domain " + domainId, e); | ||||
|                         } | ||||
|                     } else { | ||||
|                         s_logger.debug("an account with name " + admin + " already exists in the domain " + domainId); | ||||
|                     } | ||||
|                 } else { | ||||
|                     s_logger.debug("ldap user with username "+admin+" is disabled in the given group/ou"); | ||||
|                 } | ||||
|             } | ||||
|             response.setObjectName("LinkDomainToLdap"); | ||||
|             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; | ||||
|     } | ||||
| } | ||||
| @ -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.response; | ||||
| 
 | ||||
| import com.cloud.serializer.Param; | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import org.apache.cloudstack.api.ApiConstants; | ||||
| import org.apache.cloudstack.api.BaseResponse; | ||||
| 
 | ||||
| public class LinkDomainToLdapResponse extends BaseResponse { | ||||
| 
 | ||||
|     @SerializedName(ApiConstants.DOMAIN_ID) | ||||
|     @Param(description = "id of the Domain which is linked to LDAP") | ||||
|     private long domainId; | ||||
| 
 | ||||
|     @SerializedName(ApiConstants.NAME) | ||||
|     @Param(description = "name of the group or OU in LDAP which is linked to the domain") | ||||
|     private String name; | ||||
| 
 | ||||
|     @SerializedName(ApiConstants.TYPE) | ||||
|     @Param(description = "type of the name in LDAP which is linke to the domain") | ||||
|     private String type; | ||||
| 
 | ||||
|     @SerializedName(ApiConstants.ACCOUNT_TYPE) | ||||
|     @Param(description = "Type of the account to auto import") | ||||
|     private short accountType; | ||||
| 
 | ||||
|     @SerializedName(ApiConstants.ACCOUNT_ID) | ||||
|     @Param(description = "Domain Admin accountId that is created") | ||||
|     private String adminId; | ||||
| 
 | ||||
|     public LinkDomainToLdapResponse(long domainId, String type, String name, short accountType) { | ||||
|         this.domainId = domainId; | ||||
|         this.name = name; | ||||
|         this.type = type; | ||||
|         this.accountType = accountType; | ||||
|     } | ||||
| 
 | ||||
|     public long getDomainId() { | ||||
|         return domainId; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public String getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public short getAccountType() { | ||||
|         return accountType; | ||||
|     } | ||||
| 
 | ||||
|     public String getAdminId() { | ||||
|         return adminId; | ||||
|     } | ||||
| 
 | ||||
|     public void setAdminId(String adminId) { | ||||
|         this.adminId = adminId; | ||||
|     } | ||||
| } | ||||
| @ -32,7 +32,8 @@ import org.apache.log4j.Logger; | ||||
| 
 | ||||
| public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements LdapUserManager { | ||||
|     public static final Logger s_logger = Logger.getLogger(ADLdapUserManagerImpl.class.getName()); | ||||
|     private static final String MICROSOFT_AD_NESTED_MEMBERS_FILTER = "memberOf:1.2.840.113556.1.4.1941"; | ||||
|     private static final String MICROSOFT_AD_NESTED_MEMBERS_FILTER = "memberOf:1.2.840.113556.1.4.1941:"; | ||||
|     private static final String MICROSOFT_AD_MEMBERS_FILTER = "memberOf"; | ||||
| 
 | ||||
|     @Override | ||||
|     public List<LdapUser> getUsersInGroup(String groupName, LdapContext context) throws NamingException { | ||||
| @ -66,7 +67,7 @@ public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements Ld | ||||
| 
 | ||||
|         final StringBuilder memberOfFilter = new StringBuilder(); | ||||
|         String groupCnName =  _ldapConfiguration.getCommonNameAttribute() + "=" +groupName + "," +  _ldapConfiguration.getBaseDn(); | ||||
|         memberOfFilter.append("(" + MICROSOFT_AD_NESTED_MEMBERS_FILTER + ":="); | ||||
|         memberOfFilter.append("(").append(getMemberOfAttribute()).append("="); | ||||
|         memberOfFilter.append(groupCnName); | ||||
|         memberOfFilter.append(")"); | ||||
| 
 | ||||
| @ -79,4 +80,25 @@ public class ADLdapUserManagerImpl extends OpenLdapUserManagerImpl implements Ld | ||||
|         s_logger.debug("group search filter = " + result); | ||||
|         return result.toString(); | ||||
|     } | ||||
| 
 | ||||
|     protected boolean isUserDisabled(SearchResult result) throws NamingException { | ||||
|         boolean isDisabledUser = false; | ||||
|         String userAccountControl = LdapUtils.getAttributeValue(result.getAttributes(), _ldapConfiguration.getUserAccountControlAttribute()); | ||||
|         if (userAccountControl != null) { | ||||
|             int control = Integer.valueOf(userAccountControl); | ||||
|             // second bit represents disabled user flag in AD | ||||
|             if ((control & 2) > 0) { | ||||
|                 isDisabledUser = true; | ||||
|             } | ||||
|         } | ||||
|         return isDisabledUser; | ||||
|     } | ||||
| 
 | ||||
|     protected String getMemberOfAttribute() { | ||||
|         if(_ldapConfiguration.isNestedGroupsEnabled()) { | ||||
|             return MICROSOFT_AD_NESTED_MEMBERS_FILTER; | ||||
|         } else { | ||||
|             return MICROSOFT_AD_MEMBERS_FILTER; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,6 +17,9 @@ | ||||
| package org.apache.cloudstack.ldap; | ||||
| 
 | ||||
| import com.cloud.server.auth.DefaultUserAuthenticator; | ||||
| import com.cloud.user.Account; | ||||
| import com.cloud.user.AccountManager; | ||||
| import com.cloud.user.User; | ||||
| import com.cloud.user.UserAccount; | ||||
| import com.cloud.user.dao.UserAccountDao; | ||||
| import com.cloud.utils.Pair; | ||||
| @ -25,6 +28,7 @@ import org.apache.log4j.Logger; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| 
 | ||||
| public class LdapAuthenticator extends DefaultUserAuthenticator { | ||||
|     private static final Logger s_logger = Logger.getLogger(LdapAuthenticator.class.getName()); | ||||
| @ -33,6 +37,8 @@ public class LdapAuthenticator extends DefaultUserAuthenticator { | ||||
|     private LdapManager _ldapManager; | ||||
|     @Inject | ||||
|     private UserAccountDao _userAccountDao; | ||||
|     @Inject | ||||
|     private AccountManager _accountManager; | ||||
| 
 | ||||
|     public LdapAuthenticator() { | ||||
|         super(); | ||||
| @ -52,21 +58,71 @@ public class LdapAuthenticator extends DefaultUserAuthenticator { | ||||
|             return new Pair<Boolean, ActionOnFailedAuthentication>(false, null); | ||||
|         } | ||||
| 
 | ||||
|         final UserAccount user = _userAccountDao.getUserAccount(username, domainId); | ||||
| 
 | ||||
|         if (user == null) { | ||||
|             s_logger.debug("Unable to find user with " + username + " in domain " + domainId); | ||||
|             return new Pair<Boolean, ActionOnFailedAuthentication>(false, null); | ||||
|         } else if (_ldapManager.isLdapEnabled()) { | ||||
|             boolean result = _ldapManager.canAuthenticate(username, password); | ||||
|         boolean result = false; | ||||
|         ActionOnFailedAuthentication action = null; | ||||
|             if (result == false) { | ||||
|                 action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT; | ||||
| 
 | ||||
|         if (_ldapManager.isLdapEnabled()) { | ||||
|             final UserAccount user = _userAccountDao.getUserAccount(username, domainId); | ||||
|             LdapTrustMapVO ldapTrustMapVO = _ldapManager.getDomainLinkedToLdap(domainId); | ||||
|             if(ldapTrustMapVO != null) { | ||||
|                 try { | ||||
|                     LdapUser ldapUser = _ldapManager.getUser(username, ldapTrustMapVO.getType().toString(), ldapTrustMapVO.getName()); | ||||
|                     if(!ldapUser.isDisabled()) { | ||||
|                         result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password); | ||||
|                         if(result) { | ||||
|                             if(user == null) { | ||||
|                                 // import user to cloudstack | ||||
|                                 createCloudStackUserAccount(ldapUser, domainId, ldapTrustMapVO.getAccountType()); | ||||
|                             } else { | ||||
|                                 enableUserInCloudStack(user); | ||||
|                             } | ||||
|                         } | ||||
|                     } else { | ||||
|                         //disable user in cloudstack | ||||
|                         disableUserInCloudStack(user); | ||||
|                     } | ||||
|                 } catch (NoLdapUserMatchingQueryException e) { | ||||
|                     s_logger.debug(e.getMessage()); | ||||
|                 } | ||||
|             return new Pair<Boolean, ActionOnFailedAuthentication>(result, action); | ||||
| 
 | ||||
|             } else { | ||||
|             return new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT); | ||||
|                 //domain is not linked to ldap follow normal authentication | ||||
|                 if(user != null ) { | ||||
|                     try { | ||||
|                         LdapUser ldapUser = _ldapManager.getUser(username); | ||||
|                         if(!ldapUser.isDisabled()) { | ||||
|                             result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password); | ||||
|                         } else { | ||||
|                             s_logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap"); | ||||
|                         } | ||||
|                     } catch (NoLdapUserMatchingQueryException e) { | ||||
|                         s_logger.debug(e.getMessage()); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (!result && user != null) { | ||||
|                 action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return new Pair<Boolean, ActionOnFailedAuthentication>(result, action); | ||||
|     } | ||||
| 
 | ||||
|     private void enableUserInCloudStack(UserAccount user) { | ||||
|         if(user != null && (user.getState().equalsIgnoreCase(Account.State.disabled.toString()))) { | ||||
|             _accountManager.enableUser(user.getId()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void createCloudStackUserAccount(LdapUser user, long domainId, short accountType) { | ||||
|         String username = user.getUsername(); | ||||
|         _accountManager.createUserAccount(username, "", user.getFirstname(), user.getLastname(), user.getEmail(), null, username, accountType, domainId, username, null, | ||||
|                                           UUID.randomUUID().toString(), UUID.randomUUID().toString(), User.Source.LDAP); | ||||
|     } | ||||
| 
 | ||||
|     private void disableUserInCloudStack(UserAccount user) { | ||||
|         if (user != null) { | ||||
|             _accountManager.disableUser(user.getId()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -39,6 +39,9 @@ public class LdapConfiguration implements Configurable{ | ||||
|     private static final ConfigKey<String> ldapProvider = new ConfigKey<String>(String.class, "ldap.provider", "Advanced", "openldap", "ldap provider ex:openldap, microsoftad", | ||||
|                                                                                 true, ConfigKey.Scope.Global, null); | ||||
| 
 | ||||
|     private static final ConfigKey<Boolean> ldapEnableNestedGroups = new ConfigKey<Boolean>(Boolean.class, "ldap.nested.groups.enable", "Advanced", "true", | ||||
|                                                                                             "if true, nested groups will also be queried", true, ConfigKey.Scope.Global, null); | ||||
| 
 | ||||
|     private final static int scope = SearchControls.SUBTREE_SCOPE; | ||||
| 
 | ||||
|     @Inject | ||||
| @ -108,7 +111,8 @@ public class LdapConfiguration implements Configurable{ | ||||
|     } | ||||
| 
 | ||||
|     public String[] getReturnAttributes() { | ||||
|         return new String[] {getUsernameAttribute(), getEmailAttribute(), getFirstnameAttribute(), getLastnameAttribute(), getCommonNameAttribute()}; | ||||
|         return new String[] {getUsernameAttribute(), getEmailAttribute(), getFirstnameAttribute(), getLastnameAttribute(), getCommonNameAttribute(), | ||||
|                 getUserAccountControlAttribute()}; | ||||
|     } | ||||
| 
 | ||||
|     public int getScope() { | ||||
| @ -159,6 +163,10 @@ public class LdapConfiguration implements Configurable{ | ||||
|         return "cn"; | ||||
|     } | ||||
| 
 | ||||
|     public String getUserAccountControlAttribute() { | ||||
|         return "userAccountControl"; | ||||
|     } | ||||
| 
 | ||||
|     public Long getReadTimeout() { | ||||
|         return ldapReadTimeout.value(); | ||||
|     } | ||||
| @ -178,6 +186,10 @@ public class LdapConfiguration implements Configurable{ | ||||
|         return provider; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isNestedGroupsEnabled() { | ||||
|         return ldapEnableNestedGroups.value(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getConfigComponentName() { | ||||
|         return LdapConfiguration.class.getSimpleName(); | ||||
| @ -185,6 +197,6 @@ public class LdapConfiguration implements Configurable{ | ||||
| 
 | ||||
|     @Override | ||||
|     public ConfigKey<?>[] getConfigKeys() { | ||||
|         return new ConfigKey<?>[] {ldapReadTimeout, ldapPageSize, ldapProvider}; | ||||
|         return new ConfigKey<?>[] {ldapReadTimeout, ldapPageSize, ldapProvider, ldapEnableNestedGroups}; | ||||
|     } | ||||
| } | ||||
| @ -25,12 +25,15 @@ import org.apache.cloudstack.api.response.LdapUserResponse; | ||||
| import com.cloud.exception.InvalidParameterValueException; | ||||
| import com.cloud.utils.Pair; | ||||
| import com.cloud.utils.component.PluggableService; | ||||
| import org.apache.cloudstack.api.response.LinkDomainToLdapResponse; | ||||
| 
 | ||||
| public interface LdapManager extends PluggableService { | ||||
| 
 | ||||
|     enum LinkType { GROUP, OU;} | ||||
| 
 | ||||
|     LdapConfigurationResponse addConfiguration(String hostname, int port) throws InvalidParameterValueException; | ||||
| 
 | ||||
|     boolean canAuthenticate(String username, String password); | ||||
|     boolean canAuthenticate(String principal, String password); | ||||
| 
 | ||||
|     LdapConfigurationResponse createLdapConfigurationResponse(LdapConfigurationVO configuration); | ||||
| 
 | ||||
| @ -40,6 +43,8 @@ public interface LdapManager extends PluggableService { | ||||
| 
 | ||||
|     LdapUser getUser(final String username) throws NoLdapUserMatchingQueryException; | ||||
| 
 | ||||
|     LdapUser getUser(String username, String type, String name) throws NoLdapUserMatchingQueryException; | ||||
| 
 | ||||
|     List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException; | ||||
| 
 | ||||
|     List<LdapUser> getUsersInGroup(String groupName) throws NoLdapUserMatchingQueryException; | ||||
| @ -49,4 +54,8 @@ public interface LdapManager extends PluggableService { | ||||
|     Pair<List<? extends LdapConfigurationVO>, Integer> listConfigurations(LdapListConfigurationCmd cmd); | ||||
| 
 | ||||
|     List<LdapUser> searchUsers(String query) throws NoLdapUserMatchingQueryException; | ||||
| 
 | ||||
|     LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType); | ||||
| 
 | ||||
|     public LdapTrustMapVO getDomainLinkedToLdap(long domainId); | ||||
| } | ||||
| @ -25,6 +25,10 @@ import javax.inject.Inject; | ||||
| import javax.naming.NamingException; | ||||
| import javax.naming.ldap.LdapContext; | ||||
| 
 | ||||
| import org.apache.cloudstack.api.command.LinkDomainToLdapCmd; | ||||
| import org.apache.cloudstack.api.response.LinkDomainToLdapResponse; | ||||
| import org.apache.cloudstack.ldap.dao.LdapTrustMapDao; | ||||
| import org.apache.commons.lang.Validate; | ||||
| import org.apache.log4j.Logger; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| @ -61,6 +65,9 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
| 
 | ||||
|     @Inject LdapUserManagerFactory _ldapUserManagerFactory; | ||||
| 
 | ||||
|     @Inject | ||||
|     LdapTrustMapDao _ldapTrustMapDao; | ||||
| 
 | ||||
| 
 | ||||
|     public LdapManagerImpl() { | ||||
|         super(); | ||||
| @ -99,17 +106,14 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean canAuthenticate(final String username, final String password) { | ||||
|         final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); | ||||
|     public boolean canAuthenticate(final String principal, final String password) { | ||||
|         try { | ||||
|             final LdapUser user = getUser(escapedUsername); | ||||
|             final String principal = user.getPrincipal(); | ||||
|             final LdapContext context = _ldapContextFactory.createUserContext(principal, password); | ||||
|             closeContext(context); | ||||
|             return true; | ||||
|         } catch (NamingException | IOException | NoLdapUserMatchingQueryException e) { | ||||
|             s_logger.debug("Exception while doing an LDAP bind for user "+" "+username, e); | ||||
|             s_logger.info("Failed to authenticate user: " + username + ". incorrect password."); | ||||
|         } catch (NamingException | IOException e) { | ||||
|             s_logger.debug("Exception while doing an LDAP bind for user "+" "+principal, e); | ||||
|             s_logger.info("Failed to authenticate user: " + principal + ". incorrect password."); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| @ -120,7 +124,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
|                 context.close(); | ||||
|             } | ||||
|         } catch (final NamingException e) { | ||||
|             s_logger.warn(e.getMessage(),e); | ||||
|             s_logger.warn(e.getMessage(), e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -168,6 +172,7 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
|         cmdList.add(LdapImportUsersCmd.class); | ||||
|         cmdList.add(LDAPConfigCmd.class); | ||||
|         cmdList.add(LDAPRemoveCmd.class); | ||||
|         cmdList.add(LinkDomainToLdapCmd.class); | ||||
|         return cmdList; | ||||
|     } | ||||
| 
 | ||||
| @ -188,6 +193,21 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LdapUser getUser(final String username, final String type, final String name) throws NoLdapUserMatchingQueryException { | ||||
|         LdapContext context = null; | ||||
|         try { | ||||
|             context = _ldapContextFactory.createBindContext(); | ||||
|             final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username); | ||||
|             return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider()).getUser(escapedUsername, type, name, context); | ||||
|         } catch (NamingException | IOException e) { | ||||
|             s_logger.debug("ldap Exception: ",e); | ||||
|             throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + "name: " + name + "of type: " + type); | ||||
|         } finally { | ||||
|             closeContext(context); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<LdapUser> getUsers() throws NoLdapUserMatchingQueryException { | ||||
|         LdapContext context = null; | ||||
| @ -243,4 +263,22 @@ public class LdapManagerImpl implements LdapManager, LdapValidator { | ||||
|             closeContext(context); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LinkDomainToLdapResponse linkDomainToLdap(Long domainId, String type, String name, short accountType) { | ||||
|         Validate.notNull(type, "type cannot be null. It should either be GROUP or OU"); | ||||
|         Validate.notNull(domainId, "domainId cannot be null."); | ||||
|         Validate.notEmpty(name, "GROUP or OU name cannot be empty"); | ||||
|         //Account type should be 0 or 2. check the constants in com.cloud.user.Account | ||||
|         Validate.isTrue(accountType==0 || accountType==2, "accountype should be either 0(normal user) or 2(domain admin)"); | ||||
|         LinkType linkType = LdapManager.LinkType.valueOf(type.toUpperCase()); | ||||
|         LdapTrustMapVO vo = _ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, linkType, name, accountType)); | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(vo.getDomainId(), vo.getType().toString(), vo.getName(), vo.getAccountType()); | ||||
|         return response; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LdapTrustMapVO getDomainLinkedToLdap(long domainId){ | ||||
|         return _ldapTrustMapDao.findByDomainId(domainId); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,115 @@ | ||||
| /* | ||||
|  * 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_trust_map") | ||||
| public class LdapTrustMapVO implements InternalIdentity { | ||||
| 
 | ||||
|     @Id | ||||
|     @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||
|     @Column(name = "id") | ||||
|     private Long id; | ||||
| 
 | ||||
|     @Column(name = "type") | ||||
|     private LdapManager.LinkType type; | ||||
| 
 | ||||
|     @Column(name = "name") | ||||
|     private String name; | ||||
| 
 | ||||
|     @Column(name = "domain_id") | ||||
|     private long domainId; | ||||
| 
 | ||||
|     @Column(name = "account_type") | ||||
|     private short accountType; | ||||
| 
 | ||||
| 
 | ||||
|     public LdapTrustMapVO() { | ||||
|     } | ||||
| 
 | ||||
|     public LdapTrustMapVO(long domainId, LdapManager.LinkType type, String name, short accountType) { | ||||
|         this.domainId = domainId; | ||||
|         this.type = type; | ||||
|         this.name = name; | ||||
|         this.accountType = accountType; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public long getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public LdapManager.LinkType getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public long getDomainId() { | ||||
|         return domainId; | ||||
|     } | ||||
| 
 | ||||
|     public short getAccountType() { | ||||
|         return accountType; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(Object o) { | ||||
|         if (this == o) { | ||||
|             return true; | ||||
|         } | ||||
|         if (o == null || getClass() != o.getClass()) { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         LdapTrustMapVO that = (LdapTrustMapVO) o; | ||||
| 
 | ||||
|         if (domainId != that.domainId) { | ||||
|             return false; | ||||
|         } | ||||
|         if (accountType != that.accountType) { | ||||
|             return false; | ||||
|         } | ||||
|         if (type != that.type) { | ||||
|             return false; | ||||
|         } | ||||
|         return name.equals(that.name); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         int result = type.hashCode(); | ||||
|         result = 31 * result + name.hashCode(); | ||||
|         result = 31 * result + (int) (domainId ^ (domainId >>> 32)); | ||||
|         result = 31 * result + (int) accountType; | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
| @ -23,14 +23,16 @@ public class LdapUser implements Comparable<LdapUser> { | ||||
|     private final String lastname; | ||||
|     private final String username; | ||||
|     private final String domain; | ||||
|     private final boolean disabled; | ||||
| 
 | ||||
|     public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain) { | ||||
|     public LdapUser(final String username, final String email, final String firstname, final String lastname, final String principal, String domain, boolean disabled) { | ||||
|         this.username = username; | ||||
|         this.email = email; | ||||
|         this.firstname = firstname; | ||||
|         this.lastname = lastname; | ||||
|         this.principal = principal; | ||||
|         this.domain = domain; | ||||
|         this.disabled = disabled; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -74,6 +76,11 @@ public class LdapUser implements Comparable<LdapUser> { | ||||
|         return domain; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isDisabled() { | ||||
|         return disabled; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return getUsername().hashCode(); | ||||
|  | ||||
| @ -32,6 +32,8 @@ public interface LdapUserManager { | ||||
| 
 | ||||
|     public LdapUser getUser(final String username, final LdapContext context) throws NamingException, IOException; | ||||
| 
 | ||||
|     public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException; | ||||
| 
 | ||||
|     public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException; | ||||
| 
 | ||||
|     public List<LdapUser> getUsers(final String username, final LdapContext context) throws NamingException, IOException; | ||||
|  | ||||
| @ -63,7 +63,9 @@ public class OpenLdapUserManagerImpl implements LdapUserManager { | ||||
|         domain = domain.replace("," + _ldapConfiguration.getBaseDn(), ""); | ||||
|         domain = domain.replace("ou=", ""); | ||||
| 
 | ||||
|         return new LdapUser(username, email, firstname, lastname, principal, domain); | ||||
|         boolean disabled = isUserDisabled(result); | ||||
| 
 | ||||
|         return new LdapUser(username, email, firstname, lastname, principal, domain, disabled); | ||||
|     } | ||||
| 
 | ||||
|     private String generateSearchFilter(final String username) { | ||||
| @ -128,6 +130,48 @@ public class OpenLdapUserManagerImpl implements LdapUserManager { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LdapUser getUser(final String username, final String type, final String name, final LdapContext context) throws NamingException, IOException { | ||||
|         String basedn; | ||||
|         if("OU".equals(type)) { | ||||
|             basedn = name; | ||||
|         } else { | ||||
|             basedn = _ldapConfiguration.getBaseDn(); | ||||
|         } | ||||
| 
 | ||||
|         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 ("GROUP".equals(type)) { | ||||
|             memberOfFilter.append("(").append(getMemberOfAttribute()).append("="); | ||||
|             memberOfFilter.append(name); | ||||
|             memberOfFilter.append(")"); | ||||
|         } | ||||
| 
 | ||||
|         final StringBuilder searchQuery = new StringBuilder(); | ||||
|         searchQuery.append("(&"); | ||||
|         searchQuery.append(userObjectFilter); | ||||
|         searchQuery.append(usernameFilter); | ||||
|         searchQuery.append(memberOfFilter); | ||||
|         searchQuery.append(")"); | ||||
| 
 | ||||
|         return searchUser(basedn, searchQuery.toString(), context); | ||||
|     } | ||||
| 
 | ||||
|     protected String getMemberOfAttribute() { | ||||
|         return "memberof"; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<LdapUser> getUsers(final LdapContext context) throws NamingException, IOException { | ||||
|         return getUsers(null, context); | ||||
| @ -191,6 +235,30 @@ public class OpenLdapUserManagerImpl implements LdapUserManager { | ||||
|         return searchUsers(null, context); | ||||
|     } | ||||
| 
 | ||||
|     protected boolean isUserDisabled(SearchResult result) throws NamingException { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     public LdapUser searchUser(final String basedn, final String searchString, final LdapContext context) throws NamingException, IOException { | ||||
|         final SearchControls searchControls = new SearchControls(); | ||||
| 
 | ||||
|         searchControls.setSearchScope(_ldapConfiguration.getScope()); | ||||
|         searchControls.setReturningAttributes(_ldapConfiguration.getReturnAttributes()); | ||||
| 
 | ||||
|         NamingEnumeration<SearchResult> results = context.search(basedn, searchString, searchControls); | ||||
|         final List<LdapUser> users = new ArrayList<LdapUser>(); | ||||
|         while (results.hasMoreElements()) { | ||||
|             final SearchResult result = results.nextElement(); | ||||
|                 users.add(createUser(result)); | ||||
|         } | ||||
| 
 | ||||
|         if (users.size() == 1) { | ||||
|             return users.get(0); | ||||
|         } else { | ||||
|             throw new NamingException("No user found for basedn " + basedn + " and searchString " + searchString); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<LdapUser> searchUsers(final String username, final LdapContext context) throws NamingException, IOException { | ||||
| 
 | ||||
| @ -212,8 +280,10 @@ public class OpenLdapUserManagerImpl implements LdapUserManager { | ||||
|             results = context.search(basedn, generateSearchFilter(username), searchControls); | ||||
|             while (results.hasMoreElements()) { | ||||
|                 final SearchResult result = results.nextElement(); | ||||
|                 if (!isUserDisabled(result)) { | ||||
|                     users.add(createUser(result)); | ||||
|                 } | ||||
|             } | ||||
|             Control[] contextControls = context.getResponseControls(); | ||||
|             if (contextControls != null) { | ||||
|                 for (Control control : contextControls) { | ||||
|  | ||||
| @ -0,0 +1,27 @@ | ||||
| /* | ||||
|  * 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 org.apache.cloudstack.ldap.LdapTrustMapVO; | ||||
| 
 | ||||
| import com.cloud.utils.db.GenericDao; | ||||
| 
 | ||||
| public interface LdapTrustMapDao extends GenericDao<LdapTrustMapVO, Long> { | ||||
|     LdapTrustMapVO findByDomainId(long domainId); | ||||
| } | ||||
| @ -0,0 +1,48 @@ | ||||
| /* | ||||
|  * 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 javax.ejb.Local; | ||||
| 
 | ||||
| import com.cloud.utils.db.SearchBuilder; | ||||
| import com.cloud.utils.db.SearchCriteria; | ||||
| import org.apache.cloudstack.ldap.LdapTrustMapVO; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| import com.cloud.utils.db.GenericDaoBase; | ||||
| 
 | ||||
| @Component | ||||
| @Local(value = {LdapTrustMapDao.class}) | ||||
| public class LdapTrustMapDaoImpl extends GenericDaoBase<LdapTrustMapVO, Long> implements LdapTrustMapDao  { | ||||
|     private final SearchBuilder<LdapTrustMapVO> domainIdSearch; | ||||
| 
 | ||||
|     public LdapTrustMapDaoImpl() { | ||||
|         super(); | ||||
|         domainIdSearch = createSearchBuilder(); | ||||
|         domainIdSearch.and("domainId", domainIdSearch.entity().getDomainId(), SearchCriteria.Op.EQ); | ||||
|         domainIdSearch.done(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public LdapTrustMapVO findByDomainId(long domainId) { | ||||
|         final SearchCriteria<LdapTrustMapVO> sc = domainIdSearch.create(); | ||||
|         sc.setParameters("domainId", domainId); | ||||
|         return findOneBy(sc); | ||||
|     } | ||||
| } | ||||
| @ -39,10 +39,11 @@ class ADLdapUserManagerImplSpec extends spock.lang.Specification { | ||||
|         adLdapUserManager._ldapConfiguration = ldapConfiguration; | ||||
|     } | ||||
| 
 | ||||
|     def "test generate AD search filter"() { | ||||
|     def "test generate AD search filter with nested groups enabled"() { | ||||
|         ldapConfiguration.getUserObject() >> "user" | ||||
|         ldapConfiguration.getCommonNameAttribute() >> "CN" | ||||
|         ldapConfiguration.getBaseDn() >> "DC=cloud,DC=citrix,DC=com" | ||||
|         ldapConfiguration.isNestedGroupsEnabled() >> true | ||||
| 
 | ||||
|         def result = adLdapUserManager.generateADGroupSearchFilter(group); | ||||
|         expect: | ||||
| @ -52,6 +53,20 @@ class ADLdapUserManagerImplSpec extends spock.lang.Specification { | ||||
|             group << ["dev", "dev-hyd"] | ||||
|     } | ||||
| 
 | ||||
|     def "test generate AD search filter with nested groups disabled"() { | ||||
|         ldapConfiguration.getUserObject() >> "user" | ||||
|         ldapConfiguration.getCommonNameAttribute() >> "CN" | ||||
|         ldapConfiguration.getBaseDn() >> "DC=cloud,DC=citrix,DC=com" | ||||
|         ldapConfiguration.isNestedGroupsEnabled() >> false | ||||
| 
 | ||||
|         def result = adLdapUserManager.generateADGroupSearchFilter(group); | ||||
|         expect: | ||||
|         assert result.contains("memberOf=") | ||||
|         result == "(&(objectClass=user)(memberOf=CN=" + group + ",DC=cloud,DC=citrix,DC=com))" | ||||
|         where: | ||||
|         group << ["dev", "dev-hyd"] | ||||
|     } | ||||
| 
 | ||||
|     def "test getUsersInGroup null group"() { | ||||
|         ldapConfiguration.getScope() >> SearchControls.SUBTREE_SCOPE | ||||
|         ldapConfiguration.getReturnAttributes() >> ["username", "firstname", "lastname", "email"] | ||||
|  | ||||
| @ -16,12 +16,18 @@ | ||||
| // under the License. | ||||
| package groovy.org.apache.cloudstack.ldap | ||||
| 
 | ||||
| import com.cloud.server.auth.UserAuthenticator | ||||
| import com.cloud.user.Account | ||||
| import com.cloud.user.AccountManager | ||||
| import com.cloud.user.User | ||||
| import com.cloud.user.UserAccount | ||||
| 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 | ||||
| import org.apache.cloudstack.ldap.LdapTrustMapVO | ||||
| import org.apache.cloudstack.ldap.LdapUser | ||||
| 
 | ||||
| class LdapAuthenticatorSpec extends spock.lang.Specification { | ||||
| 
 | ||||
| @ -40,7 +46,10 @@ class LdapAuthenticatorSpec extends spock.lang.Specification { | ||||
|     def "Test failed authentication due to ldap bind being unsuccessful"() { | ||||
|         given: "We have an LdapManager, LdapConfiguration, userAccountDao and LdapAuthenticator" | ||||
|         def ldapManager = Mock(LdapManager) | ||||
|         def ldapUser = Mock(LdapUser) | ||||
|         ldapUser.isDisabled() >> false | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         ldapManager.getUser("rmurphy") >> ldapUser | ||||
|         ldapManager.canAuthenticate(_, _) >> false | ||||
| 
 | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
| @ -72,8 +81,11 @@ class LdapAuthenticatorSpec extends spock.lang.Specification { | ||||
|     def "Test successful authentication"() { | ||||
|         given: "We have an LdapManager, LdapConfiguration, userAccountDao and LdapAuthenticator" | ||||
|         def ldapManager = Mock(LdapManager) | ||||
|         def ldapUser = Mock(LdapUser) | ||||
|         ldapUser.isDisabled() >> false | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         ldapManager.canAuthenticate(_, _) >> true | ||||
|         ldapManager.getUser("rmurphy") >> ldapUser | ||||
| 
 | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         userAccountDao.getUserAccount(_, _) >> new UserAccountVO() | ||||
| @ -96,4 +108,142 @@ class LdapAuthenticatorSpec extends spock.lang.Specification { | ||||
|         then: "it doesn't change" | ||||
|         result == "password" | ||||
|     } | ||||
| 
 | ||||
|     def "test authentication when ldap is disabled"(){ | ||||
|         LdapManager ldapManager = Mock(LdapManager) | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         def ldapAuthenticator = new LdapAuthenticator(ldapManager, userAccountDao) | ||||
|         ldapManager.isLdapEnabled() >> false | ||||
| 
 | ||||
|         when: | ||||
|             Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate("rajanik", "password", 1, null) | ||||
|         then: | ||||
|             result.first() == false | ||||
|             result.second() == null | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     // tests when domain is linked to LDAP | ||||
|     def "test authentication when domain is linked and user disabled in ldap"(){ | ||||
|         LdapManager ldapManager = Mock(LdapManager) | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         AccountManager accountManager = Mock(AccountManager) | ||||
| 
 | ||||
|         def ldapAuthenticator = new LdapAuthenticator() | ||||
|         ldapAuthenticator._ldapManager = ldapManager | ||||
|         ldapAuthenticator._userAccountDao = userAccountDao | ||||
|         ldapAuthenticator._accountManager = accountManager | ||||
| 
 | ||||
|         long domainId = 1; | ||||
|         String username = "rajanik" | ||||
|         LdapManager.LinkType type = LdapManager.LinkType.GROUP | ||||
|         String name = "CN=test,DC=ccp,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         UserAccount userAccount = Mock(UserAccount) | ||||
|         userAccountDao.getUserAccount(username, domainId) >> userAccount | ||||
|         userAccount.getId() >> 1 | ||||
|         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2) | ||||
|         ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true) | ||||
|         //user should be disabled in cloudstack | ||||
|         accountManager.disableUser(1) >> userAccount | ||||
| 
 | ||||
|         when: | ||||
|             Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null) | ||||
|         then: | ||||
|             result.first() == false | ||||
|             result.second() == UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT | ||||
|     } | ||||
| 
 | ||||
|     def "test authentication when domain is linked and first time user can authenticate in ldap"(){ | ||||
|         LdapManager ldapManager = Mock(LdapManager) | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         AccountManager accountManager = Mock(AccountManager) | ||||
| 
 | ||||
|         def ldapAuthenticator = new LdapAuthenticator() | ||||
|         ldapAuthenticator._ldapManager = ldapManager | ||||
|         ldapAuthenticator._userAccountDao = userAccountDao | ||||
|         ldapAuthenticator._accountManager = accountManager | ||||
| 
 | ||||
|         long domainId = 1; | ||||
|         String username = "rajanik" | ||||
|         LdapManager.LinkType type = LdapManager.LinkType.GROUP | ||||
|         String name = "CN=test,DC=ccp,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         userAccountDao.getUserAccount(username, domainId) >> null | ||||
|         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)0) | ||||
|         ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false) | ||||
|         ldapManager.canAuthenticate(_,_) >> true | ||||
|         //user should be created in cloudstack | ||||
|         accountManager.createUserAccount(username, "", "firstname", "lastname", "email", null, username, (short) 2, domainId, username, null, _, _, User.Source.LDAP) >> Mock(UserAccount) | ||||
| 
 | ||||
|         when: | ||||
|             Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null) | ||||
|         then: | ||||
|             result.first() == true | ||||
|             result.second() == null | ||||
|     } | ||||
| 
 | ||||
|     def "test authentication when domain is linked and existing user can authenticate in ldap"(){ | ||||
|         LdapManager ldapManager = Mock(LdapManager) | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         AccountManager accountManager = Mock(AccountManager) | ||||
| 
 | ||||
|         def ldapAuthenticator = new LdapAuthenticator() | ||||
|         ldapAuthenticator._ldapManager = ldapManager | ||||
|         ldapAuthenticator._userAccountDao = userAccountDao | ||||
|         ldapAuthenticator._accountManager = accountManager | ||||
| 
 | ||||
|         long domainId = 1; | ||||
|         String username = "rajanik" | ||||
|         LdapManager.LinkType type = LdapManager.LinkType.GROUP | ||||
|         String name = "CN=test,DC=ccp,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         UserAccount userAccount = Mock(UserAccount) | ||||
|         userAccountDao.getUserAccount(username, domainId) >> userAccount | ||||
|         userAccount.getId() >> 1 | ||||
|         userAccount.getState() >> Account.State.disabled.toString() | ||||
|         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2) | ||||
|         ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false) | ||||
|         ldapManager.canAuthenticate(_,_) >> true | ||||
|         //user should be enabled in cloudstack if disabled | ||||
|         accountManager.enableUser(1) >> userAccount | ||||
| 
 | ||||
|         when: | ||||
|         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null) | ||||
|         then: | ||||
|         result.first() == true | ||||
|         result.second() == null | ||||
|     } | ||||
| 
 | ||||
|     def "test authentication when domain is linked and user cannot authenticate in ldap"(){ | ||||
|         LdapManager ldapManager = Mock(LdapManager) | ||||
|         UserAccountDao userAccountDao = Mock(UserAccountDao) | ||||
|         AccountManager accountManager = Mock(AccountManager) | ||||
| 
 | ||||
|         def ldapAuthenticator = new LdapAuthenticator() | ||||
|         ldapAuthenticator._ldapManager = ldapManager | ||||
|         ldapAuthenticator._userAccountDao = userAccountDao | ||||
|         ldapAuthenticator._accountManager = accountManager | ||||
| 
 | ||||
|         long domainId = 1; | ||||
|         String username = "rajanik" | ||||
|         LdapManager.LinkType type = LdapManager.LinkType.GROUP | ||||
|         String name = "CN=test,DC=ccp,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapManager.isLdapEnabled() >> true | ||||
|         UserAccount userAccount = Mock(UserAccount) | ||||
|         userAccountDao.getUserAccount(username, domainId) >> userAccount | ||||
|         ldapManager.getDomainLinkedToLdap(domainId) >> new LdapTrustMapVO(domainId, type, name, (short)2) | ||||
|         ldapManager.getUser(username, type.toString(), name) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false) | ||||
|         ldapManager.canAuthenticate(_,_) >> false | ||||
| 
 | ||||
|         when: | ||||
|         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> result = ldapAuthenticator.authenticate(username, "password", domainId, null) | ||||
|         then: | ||||
|             result.first() == false | ||||
|             result.second() == UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -127,7 +127,7 @@ class LdapConfigurationSpec extends spock.lang.Specification { | ||||
|         when: "Get return attributes is called" | ||||
|         String[] returnAttributes = ldapConfiguration.getReturnAttributes() | ||||
|         then: "An array containing uid, mail, givenname, sn and cn is returned" | ||||
|         returnAttributes == ["uid", "mail", "givenname", "sn", "cn"] | ||||
|         returnAttributes == ["uid", "mail", "givenname", "sn", "cn", "userAccountControl"] | ||||
|     } | ||||
| 
 | ||||
|     def "Test that getScope returns SearchControls.SUBTREE_SCOPE"() { | ||||
|  | ||||
| @ -53,7 +53,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { | ||||
|     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,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         ldapManager.getUser(_) >> new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false) | ||||
|         AccountService accountService = Mock(AccountService) | ||||
|         def ldapCreateAccountCmd = Spy(LdapCreateAccountCmd, constructorArgs: [ldapManager, accountService]) | ||||
|         ldapCreateAccountCmd.getCurrentContext() >> Mock(CallContext) | ||||
| @ -105,7 +105,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { | ||||
|         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", "domain")) | ||||
|         def result = ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", "lastname", "principal", "domain", false)) | ||||
|         then: "the result is true" | ||||
|         result == true | ||||
|     } | ||||
| @ -116,7 +116,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { | ||||
|         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", "domain")) | ||||
|         ldapCreateAccountCmd.validateUser(new LdapUser("username", null, "firstname", "lastname", "principal", "domain", false)) | ||||
|         then: "An exception is thrown" | ||||
|         thrown Exception | ||||
|     } | ||||
| @ -127,7 +127,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { | ||||
|         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")) | ||||
|         ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", null, "lastname", "principal", false)) | ||||
|         then: "An exception is thrown" | ||||
|         thrown Exception | ||||
|     } | ||||
| @ -138,7 +138,7 @@ class LdapCreateAccountCmdSpec extends spock.lang.Specification { | ||||
|         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", "domain")) | ||||
|         ldapCreateAccountCmd.validateUser(new LdapUser("username", "email", "firstname", null, "principal", "domain", false)) | ||||
|         then: "An exception is thown" | ||||
|         thrown Exception | ||||
|     } | ||||
|  | ||||
| @ -53,8 +53,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         def accountService = Mock(AccountService) | ||||
| 
 | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsers() >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
| @ -81,8 +81,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         def accountService = Mock(AccountService) | ||||
| 
 | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsersInGroup("TestGroup") >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
| @ -110,8 +110,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         def accountService = Mock(AccountService) | ||||
| 
 | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsersInGroup("TestGroup") >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
| @ -139,8 +139,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         def accountService = Mock(AccountService) | ||||
| 
 | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         users.add(new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsers() >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         LdapUserResponse response2 = new LdapUserResponse("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
| @ -169,8 +169,8 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         ldapImportUsersCmd.domainId = varDomainId | ||||
|         ldapImportUsersCmd.groupName = varGroupName | ||||
| 
 | ||||
|         def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering"); | ||||
|         def ldapUser1 = new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false) | ||||
|         def ldapUser2 = new LdapUser("bob", "bob@test.com", "Robert", "Young", "cn=bob,ou=engineering,dc=cloudstack,dc=org", "engineering", false); | ||||
| 
 | ||||
|         Domain domain = new DomainVO(expectedDomainName, 1L, 1L, expectedDomainName, UUID.randomUUID().toString()); | ||||
|         if (varDomainId != null) { | ||||
| @ -204,7 +204,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" | ||||
|         def ldapManager = Mock(LdapManager) | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsers() >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         ldapManager.createLdapUserResponse(_) >>> response1 | ||||
| @ -234,7 +234,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" | ||||
|         def ldapManager = Mock(LdapManager) | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsers() >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         ldapManager.createLdapUserResponse(_) >>> response1 | ||||
| @ -263,7 +263,7 @@ class LdapImportUsersCmdSpec extends spock.lang.Specification { | ||||
|         given: "We have an LdapManager, DomainService, two users and a LdapImportUsersCmd" | ||||
|         def ldapManager = Mock(LdapManager) | ||||
|         List<LdapUser> users = new ArrayList() | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapManager.getUsers() >> users | ||||
|         LdapUserResponse response1 = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering") | ||||
|         ldapManager.createLdapUserResponse(_) >>> response1 | ||||
|  | ||||
| @ -53,7 +53,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification { | ||||
| 		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", null)) | ||||
| 		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)) | ||||
| 		ldapManager.getUsers() >> users | ||||
| 		LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) | ||||
| 		ldapManager.createLdapUserResponse(_) >> response | ||||
| @ -92,7 +92,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification { | ||||
| 
 | ||||
| 		queryService.searchForUsers(_) >> queryServiceResponse | ||||
| 
 | ||||
| 		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) | ||||
| 		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false) | ||||
| 		def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService) | ||||
| 
 | ||||
| 		when: "isACloudstackUser is executed" | ||||
| @ -109,7 +109,7 @@ class LdapListUsersCmdSpec extends spock.lang.Specification { | ||||
| 
 | ||||
| 		queryService.searchForUsers(_) >> new ListResponse<UserResponse>() | ||||
| 
 | ||||
| 		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) | ||||
| 		def ldapUser = new LdapUser("rmurphy", "rmurphy@cloudstack.org", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false) | ||||
| 		def ldapListUsersCmd = new LdapListUsersCmd(ldapManager,queryService) | ||||
| 
 | ||||
| 		when: "isACloudstackUser is executed" | ||||
|  | ||||
| @ -24,6 +24,9 @@ import org.apache.cloudstack.api.command.LdapDeleteConfigurationCmd | ||||
| import org.apache.cloudstack.api.command.LdapImportUsersCmd | ||||
| import org.apache.cloudstack.api.command.LdapListUsersCmd | ||||
| import org.apache.cloudstack.api.command.LdapUserSearchCmd | ||||
| import org.apache.cloudstack.api.command.LinkDomainToLdapCmd | ||||
| import org.apache.cloudstack.api.response.LinkDomainToLdapResponse | ||||
| import org.apache.cloudstack.ldap.dao.LdapTrustMapDao | ||||
| 
 | ||||
| import javax.naming.NamingException | ||||
| import javax.naming.ldap.InitialLdapContext | ||||
| @ -35,6 +38,8 @@ import org.apache.cloudstack.ldap.dao.LdapConfigurationDaoImpl | ||||
| import com.cloud.exception.InvalidParameterValueException | ||||
| import com.cloud.utils.Pair | ||||
| 
 | ||||
| import javax.naming.ldap.LdapContext | ||||
| 
 | ||||
| class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|     def "Test failing of getUser due to bind issue"() { | ||||
|         given: "We have an LdapConfigurationDao, LdapContextFactory, LdapUserManager and LdapManager" | ||||
| @ -111,7 +116,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) | ||||
|         when: "A ldap user response is generated" | ||||
|         def result = ldapManager.createLdapUserResponse(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", | ||||
|                 "engineering")) | ||||
|                 "engineering", false)) | ||||
|         then: "The result of the response should match the given ldap user" | ||||
|         result.username == "rmurphy" | ||||
|         result.email == "rmurphy@test.com" | ||||
| @ -131,7 +136,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         ldapUserManagerFactory.getInstance(_) >> 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", null)) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)) | ||||
|         ldapUserManager.getUsers(_) >> users; | ||||
|         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) | ||||
|         when: "We search for a group of users" | ||||
| @ -149,7 +154,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         def ldapConfiguration = Mock(LdapConfiguration) | ||||
|         ldapUserManagerFactory.getInstance(_) >> ldapUserManager | ||||
|         ldapContextFactory.createBindContext() >> null | ||||
|         ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) | ||||
|         ldapUserManager.getUser(_, _) >> new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false) | ||||
|         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) | ||||
|         when: "We search for a user" | ||||
|         def result = ldapManager.getUser("rmurphy") | ||||
| @ -194,22 +199,6 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         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 ldapUserManagerFactory = Mock(LdapUserManagerFactory) | ||||
|         ldapUserManagerFactory.getInstance(_) >> ldapUserManager | ||||
|         def ldapConfiguration = Mock(LdapConfiguration) | ||||
|         def ldapManager = Spy(LdapManagerImpl, constructorArgs: [ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration]) | ||||
|         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) | ||||
| @ -293,7 +282,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         ldapContextFactory.createBindContext() >> null; | ||||
| 
 | ||||
|         List<LdapUser> users = new ArrayList<LdapUser>(); | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,ou=engineering,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapUserManager.getUsers(_, _) >> users; | ||||
| 
 | ||||
|         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) | ||||
| @ -364,6 +353,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         cmdList.add(LdapImportUsersCmd.class); | ||||
|         cmdList.add(LDAPConfigCmd.class); | ||||
|         cmdList.add(LDAPRemoveCmd.class); | ||||
|         cmdList.add(LinkDomainToLdapCmd.class) | ||||
|         return cmdList | ||||
|     } | ||||
| 
 | ||||
| @ -434,7 +424,7 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         ldapUserManagerFactory.getInstance(_) >> 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", "engineering")) | ||||
|         users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", "engineering", false)) | ||||
|         ldapUserManager.getUsersInGroup("engineering", _) >> users; | ||||
|         def ldapManager = new LdapManagerImpl(ldapConfigurationDao, ldapContextFactory, ldapUserManagerFactory, ldapConfiguration) | ||||
|         when: "We search for a group of users" | ||||
| @ -442,4 +432,154 @@ class LdapManagerImplSpec extends spock.lang.Specification { | ||||
|         then: "A list greater of size one is returned" | ||||
|         result.size() == 1; | ||||
|     } | ||||
| 
 | ||||
|     def "test linkDomainToLdap invalid ldap group type"() { | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         LdapTrustMapDao ldapTrustMapDao = Mock(LdapTrustMapDao) | ||||
|         ldapManager._ldapTrustMapDao = ldapTrustMapDao | ||||
| 
 | ||||
|         def domainId = 1 | ||||
|         when: | ||||
|             println("using type: " + type) | ||||
|             LinkDomainToLdapResponse response = ldapManager.linkDomainToLdap(domainId, type, "CN=test,DC=CCP,DC=Citrix,DC=Com", (short)2) | ||||
|         then: | ||||
|             thrown(IllegalArgumentException) | ||||
|         where: | ||||
|             type << ["", null, "TEST", "TEST TEST"] | ||||
|     } | ||||
|     def "test linkDomainToLdap invalid domain"() { | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         LdapTrustMapDao ldapTrustMapDao = Mock(LdapTrustMapDao) | ||||
|         ldapManager._ldapTrustMapDao = ldapTrustMapDao | ||||
| 
 | ||||
|         when: | ||||
|             LinkDomainToLdapResponse response = ldapManager.linkDomainToLdap(null, "GROUP", "CN=test,DC=CCP,DC=Citrix,DC=Com", (short)2) | ||||
|         then: | ||||
|             thrown(IllegalArgumentException) | ||||
|     } | ||||
|     def "test linkDomainToLdap invalid ldap name"() { | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         LdapTrustMapDao ldapTrustMapDao = Mock(LdapTrustMapDao) | ||||
|         ldapManager._ldapTrustMapDao = ldapTrustMapDao | ||||
| 
 | ||||
|         def domainId = 1 | ||||
|         when: | ||||
|         println("using name: " + name) | ||||
|             LinkDomainToLdapResponse response = ldapManager.linkDomainToLdap(domainId, "GROUP", name, (short)2) | ||||
|         then: | ||||
|             thrown(IllegalArgumentException) | ||||
|         where: | ||||
|             name << ["", null] | ||||
|     } | ||||
|     def "test linkDomainToLdap invalid accountType"(){ | ||||
| 
 | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         LdapTrustMapDao ldapTrustMapDao = Mock(LdapTrustMapDao) | ||||
|         ldapManager._ldapTrustMapDao = ldapTrustMapDao | ||||
| 
 | ||||
|         def domainId = 1 | ||||
|         when: | ||||
|             println("using accountType: " + accountType) | ||||
|             LinkDomainToLdapResponse response = ldapManager.linkDomainToLdap(domainId, "GROUP", "TEST", (short)accountType) | ||||
|         then: | ||||
|             thrown(IllegalArgumentException) | ||||
|         where: | ||||
|             accountType << [-1, 1, 3, 4, 5, 6, 20000, -500000] | ||||
|     } | ||||
|     def "test linkDomainToLdap when all is well"(){ | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         LdapTrustMapDao ldapTrustMapDao = Mock(LdapTrustMapDao) | ||||
|         ldapManager._ldapTrustMapDao = ldapTrustMapDao | ||||
| 
 | ||||
|         def domainId=1 | ||||
|         def type=LdapManager.LinkType.GROUP | ||||
|         def name="CN=test,DC=CCP, DC=citrix,DC=com" | ||||
|         short accountType=2 | ||||
| 
 | ||||
|         1 * ldapTrustMapDao.persist(new LdapTrustMapVO(domainId, type, name, accountType)) >> new LdapTrustMapVO(domainId, type, name, accountType) | ||||
| 
 | ||||
|         when: | ||||
|             LinkDomainToLdapResponse response = ldapManager.linkDomainToLdap(domainId, type.toString(), name, accountType) | ||||
|         then: | ||||
|             response.getDomainId() == domainId | ||||
|             response.getType() == type.toString() | ||||
|             response.getName() == name | ||||
|             response.getAccountType() == accountType | ||||
|     } | ||||
| 
 | ||||
|     def "test getUser(username,type,group) when username disabled in ldap"(){ | ||||
|         def ldapUserManager = Mock(LdapUserManager) | ||||
|         def ldapUserManagerFactory = Mock(LdapUserManagerFactory) | ||||
|         ldapUserManagerFactory.getInstance(_) >> ldapUserManager | ||||
|         def ldapContextFactory = Mock(LdapContextFactory) | ||||
|         ldapContextFactory.createBindContext() >> Mock(LdapContext) | ||||
|         def ldapConfiguration = Mock(LdapConfiguration) | ||||
| 
 | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         ldapManager._ldapUserManagerFactory = ldapUserManagerFactory | ||||
|         ldapManager._ldapContextFactory = ldapContextFactory | ||||
|         ldapManager._ldapConfiguration = ldapConfiguration | ||||
| 
 | ||||
|         def username = "admin" | ||||
|         def type = "GROUP" | ||||
|         def name = "CN=test,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", true) | ||||
| 
 | ||||
|         when: | ||||
|             LdapUser user = ldapManager.getUser(username, type, name) | ||||
|         then: | ||||
|             user.getUsername() == username | ||||
|             user.isDisabled() == true | ||||
|     } | ||||
| 
 | ||||
|     def "test getUser(username,type,group) when username doesnt exist in ldap"(){ | ||||
|         def ldapUserManager = Mock(LdapUserManager) | ||||
|         def ldapUserManagerFactory = Mock(LdapUserManagerFactory) | ||||
|         ldapUserManagerFactory.getInstance(_) >> ldapUserManager | ||||
|         def ldapContextFactory = Mock(LdapContextFactory) | ||||
|         ldapContextFactory.createBindContext() >> Mock(LdapContext) | ||||
|         def ldapConfiguration = Mock(LdapConfiguration) | ||||
| 
 | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         ldapManager._ldapUserManagerFactory = ldapUserManagerFactory | ||||
|         ldapManager._ldapContextFactory = ldapContextFactory | ||||
|         ldapManager._ldapConfiguration = ldapConfiguration | ||||
| 
 | ||||
|         def username = "admin" | ||||
|         def type = "GROUP" | ||||
|         def name = "CN=test,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapUserManager.getUser(username, type, name, _) >> { throw new NamingException("Test naming exception") } | ||||
| 
 | ||||
|         when: | ||||
|             LdapUser user = ldapManager.getUser(username, type, name) | ||||
|         then: | ||||
|             thrown(NoLdapUserMatchingQueryException) | ||||
|     } | ||||
|     def "test getUser(username,type,group) when username is an active member of the group in ldap"(){ | ||||
|         def ldapUserManager = Mock(LdapUserManager) | ||||
|         def ldapUserManagerFactory = Mock(LdapUserManagerFactory) | ||||
|         ldapUserManagerFactory.getInstance(_) >> ldapUserManager | ||||
|         def ldapContextFactory = Mock(LdapContextFactory) | ||||
|         ldapContextFactory.createBindContext() >> Mock(LdapContext) | ||||
|         def ldapConfiguration = Mock(LdapConfiguration) | ||||
| 
 | ||||
|         def ldapManager = new LdapManagerImpl() | ||||
|         ldapManager._ldapUserManagerFactory = ldapUserManagerFactory | ||||
|         ldapManager._ldapContextFactory = ldapContextFactory | ||||
|         ldapManager._ldapConfiguration = ldapConfiguration | ||||
| 
 | ||||
|         def username = "admin" | ||||
|         def type = "GROUP" | ||||
|         def name = "CN=test,DC=citrix,DC=com" | ||||
| 
 | ||||
|         ldapUserManager.getUser(username, type, name, _) >> new LdapUser(username, "email", "firstname", "lastname", "principal", "domain", false) | ||||
| 
 | ||||
|         when: | ||||
|         LdapUser user = ldapManager.getUser(username, type, name) | ||||
|         then: | ||||
|         user.getUsername() == username | ||||
|         user.isDisabled() == false | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -48,7 +48,7 @@ class LdapSearchUserCmdSpec extends spock.lang.Specification { | ||||
| 	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", null)) | ||||
| 		users.add(new LdapUser("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null, false)) | ||||
| 		ldapManager.searchUsers(_) >> users | ||||
| 		LdapUserResponse response = new LdapUserResponse("rmurphy", "rmurphy@test.com", "Ryan", "Murphy", "cn=rmurphy,dc=cloudstack,dc=org", null) | ||||
| 		ldapManager.createLdapUserResponse(_) >> response | ||||
|  | ||||
| @ -22,7 +22,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     def "Testing LdapUsers hashCode generation"() { | ||||
| 		given: | ||||
| 		def userA = new LdapUser(usernameA, "", "", "", "", "") | ||||
| 		def userA = new LdapUser(usernameA, "", "", "", "", "", false) | ||||
| 		expect: | ||||
| 		userA.hashCode() == usernameA.hashCode() | ||||
| 		where: | ||||
| @ -31,8 +31,8 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "", "", "", "", "") | ||||
| 		def userA = new LdapUser(usernameA, "", "", "", "", "", false) | ||||
| 		def userB = new LdapUser(usernameB, "", "", "", "", "", false) | ||||
| 		expect: "That when compared the result is less than or equal to 0" | ||||
| 		userA.compareTo(userB) <= 0 | ||||
| 		where: "The following values are used" | ||||
| @ -43,8 +43,8 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     def "Testing that LdapUsers equality"() { | ||||
| 		given: | ||||
| 		def userA = new LdapUser(usernameA, "", "", "", "", "") | ||||
| 		def userB = new LdapUser(usernameB, "", "", "", "", "") | ||||
| 		def userA = new LdapUser(usernameA, "", "", "", "", "", false) | ||||
| 		def userB = new LdapUser(usernameB, "", "", "", "", "", false) | ||||
| 		expect: | ||||
| 		userA.equals(userA) == true | ||||
| 		userA.equals(new Object()) == false | ||||
| @ -56,7 +56,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "", "", "", "", "") | ||||
| 	def user = new LdapUser(username, "", "", "", "", "", false) | ||||
|         expect: "The username is equal to the given data source" | ||||
|         user.getUsername() == username | ||||
|         where: "The username is set to " | ||||
| @ -65,7 +65,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "", "", "", "") | ||||
| 	def user = new LdapUser("", email, "", "", "", "", false) | ||||
|         expect: "The email is equal to the given data source" | ||||
|         user.getEmail() == email | ||||
|         where: "The email is set to " | ||||
| @ -74,7 +74,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "", "", "") | ||||
| 	def user = new LdapUser("", "", firstname, "", "", "", false) | ||||
|         expect: "The firstname is equal to the given data source" | ||||
|         user.getFirstname() == firstname | ||||
|         where: "The firstname is set to " | ||||
| @ -83,7 +83,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "", "") | ||||
| 	def user = new LdapUser("", "", "", lastname, "", "", false) | ||||
|         expect: "The lastname is equal to the given data source" | ||||
|         user.getLastname() == lastname | ||||
|         where: "The lastname is set to " | ||||
| @ -92,7 +92,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     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, "") | ||||
| 	def user = new LdapUser("", "", "", "", principal, "", false) | ||||
|         expect: "The principal is equal to the given data source" | ||||
|         user.getPrincipal() == principal | ||||
| 	where: "The principal is set to " | ||||
| @ -101,7 +101,7 @@ class LdapUserSpec extends spock.lang.Specification { | ||||
| 
 | ||||
|     def "Testing the domain is correctly set with the ldap object"() { | ||||
| 	given: "You have created a LDAP user object with a principal" | ||||
| 	def user = new LdapUser("", "", "", "", "", domain) | ||||
| 	def user = new LdapUser("", "", "", "", "", domain, false) | ||||
| 	expect: "The principal is equal to the given data source" | ||||
| 	user.getDomain() == domain | ||||
| 	where: "The username is set to " | ||||
|  | ||||
| @ -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 groovy.org.apache.cloudstack.ldap | ||||
| 
 | ||||
| import com.cloud.exception.InvalidParameterValueException | ||||
| import com.cloud.user.Account | ||||
| import com.cloud.user.AccountService | ||||
| import com.cloud.user.User | ||||
| import com.cloud.user.UserAccount | ||||
| import org.apache.cloudstack.api.ServerApiException | ||||
| import org.apache.cloudstack.api.command.LinkDomainToLdapCmd | ||||
| import org.apache.cloudstack.api.response.LinkDomainToLdapResponse | ||||
| import org.apache.cloudstack.ldap.LdapManager | ||||
| import org.apache.cloudstack.ldap.LdapUser | ||||
| import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException | ||||
| import spock.lang.Shared | ||||
| import spock.lang.Specification | ||||
| 
 | ||||
| class LinkDomainToLdapCmdSpec extends Specification { | ||||
| 
 | ||||
|     @Shared | ||||
|     private LdapManager _ldapManager; | ||||
| 
 | ||||
|     @Shared | ||||
|     public AccountService _accountService; | ||||
| 
 | ||||
|     @Shared | ||||
|     public LinkDomainToLdapCmd linkDomainToLdapCmd; | ||||
| 
 | ||||
|     def setup() { | ||||
|         _ldapManager = Mock(LdapManager) | ||||
|         _accountService = Mock(AccountService) | ||||
| 
 | ||||
|         linkDomainToLdapCmd = new LinkDomainToLdapCmd() | ||||
|         linkDomainToLdapCmd._accountService = _accountService | ||||
|         linkDomainToLdapCmd._ldapManager = _ldapManager | ||||
|     } | ||||
| 
 | ||||
|     def "test invalid params"() { | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> {throw new InvalidParameterValueException("invalid param")} | ||||
|         when: | ||||
|             linkDomainToLdapCmd.execute(); | ||||
|         then: | ||||
|             thrown(ServerApiException) | ||||
|     } | ||||
|     def "test valid params without admin"(){ | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(1, "GROUP", "CN=test,DC=ccp,DC=citrix,DC=com", (short)2) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         when: | ||||
|             linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|             LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|             result.getObjectName() == "LinkDomainToLdap" | ||||
|             result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|     } | ||||
| 
 | ||||
|     def "test with valid params and with disabled admin"() { | ||||
|         def domainId = 1; | ||||
|         def type = "GROUP"; | ||||
|         def name = "CN=test,DC=ccp,DC=Citrix,DC=com" | ||||
|         def accountType = 2; | ||||
|         def username = "admin" | ||||
| 
 | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", true) | ||||
| 
 | ||||
|         linkDomainToLdapCmd.admin = username | ||||
|         linkDomainToLdapCmd.type = type | ||||
|         linkDomainToLdapCmd.name = name | ||||
|         linkDomainToLdapCmd.domainId = domainId | ||||
| 
 | ||||
|         when: | ||||
|         linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|         LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|         result.getObjectName() == "LinkDomainToLdap" | ||||
|         result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|         result.getDomainId() == domainId | ||||
|         result.getType() == type | ||||
|         result.getName() == name | ||||
|         result.getAdminId() == null | ||||
|     } | ||||
| 
 | ||||
|     def "test with valid params and with admin who exist in cloudstack already"() { | ||||
|         def domainId = 1; | ||||
|         def type = "GROUP"; | ||||
|         def name = "CN=test,DC=ccp,DC=Citrix,DC=com" | ||||
|         def accountType = 2; | ||||
|         def username = "admin" | ||||
| 
 | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false) | ||||
| 
 | ||||
|         _accountService.getActiveAccountByName(username, domainId) >> Mock(Account) | ||||
| 
 | ||||
|         linkDomainToLdapCmd.admin = username | ||||
|         linkDomainToLdapCmd.type = type | ||||
|         linkDomainToLdapCmd.name = name | ||||
|         linkDomainToLdapCmd.domainId = domainId | ||||
| 
 | ||||
|         when: | ||||
|         linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|         LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|         result.getObjectName() == "LinkDomainToLdap" | ||||
|         result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|         result.getDomainId() == domainId | ||||
|         result.getType() == type | ||||
|         result.getName() == name | ||||
|         result.getAdminId() == null | ||||
|     } | ||||
| 
 | ||||
|     def "test with valid params and with admin who doesnt exist in cloudstack"() { | ||||
|         def domainId = 1; | ||||
|         def type = "GROUP"; | ||||
|         def name = "CN=test,DC=ccp,DC=Citrix,DC=com" | ||||
|         def accountType = 2; | ||||
|         def username = "admin" | ||||
|         def accountId = 24 | ||||
| 
 | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false) | ||||
| 
 | ||||
|         _accountService.getActiveAccountByName(username, domainId) >> null | ||||
|         UserAccount userAccount = Mock(UserAccount) | ||||
|         userAccount.getAccountId() >> 24 | ||||
|         _accountService.createUserAccount(username, "", "Admin", "Admin", "admin@ccp.citrix.com", null, username, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, domainId, | ||||
|                 username, null, _, _, User.Source.LDAP) >> userAccount | ||||
| 
 | ||||
|         linkDomainToLdapCmd.admin = username | ||||
|         linkDomainToLdapCmd.type = type | ||||
|         linkDomainToLdapCmd.name = name | ||||
|         linkDomainToLdapCmd.domainId = domainId | ||||
| 
 | ||||
|         when: | ||||
|         linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|         LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|         result.getObjectName() == "LinkDomainToLdap" | ||||
|         result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|         result.getDomainId() == domainId | ||||
|         result.getType() == type | ||||
|         result.getName() == name | ||||
|         result.getAdminId() == String.valueOf(accountId) | ||||
|     } | ||||
| 
 | ||||
|     def "test when admin doesnt exist in ldap"() { | ||||
|         def domainId = 1; | ||||
|         def type = "GROUP"; | ||||
|         def name = "CN=test,DC=ccp,DC=Citrix,DC=com" | ||||
|         def accountType = 2; | ||||
|         def username = "admin" | ||||
| 
 | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         _ldapManager.getUser(username, type, name) >> {throw new NoLdapUserMatchingQueryException("get ldap user failed from mock")} | ||||
| 
 | ||||
|         linkDomainToLdapCmd.admin = username | ||||
|         linkDomainToLdapCmd.type = type | ||||
|         linkDomainToLdapCmd.name = name | ||||
|         linkDomainToLdapCmd.domainId = domainId | ||||
| 
 | ||||
|         when: | ||||
|         linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|         LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|         result.getObjectName() == "LinkDomainToLdap" | ||||
|         result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|         result.getDomainId() == domainId | ||||
|         result.getType() == type | ||||
|         result.getName() == name | ||||
|         result.getAdminId() == null | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * api should not fail in this case as link domain to ldap is successful | ||||
|      */ | ||||
|     def "test when create user account throws a run time exception"() { | ||||
|         def domainId = 1; | ||||
|         def type = "GROUP"; | ||||
|         def name = "CN=test,DC=ccp,DC=Citrix,DC=com" | ||||
|         def accountType = 2; | ||||
|         def username = "admin" | ||||
|         def accountId = 24 | ||||
| 
 | ||||
|         LinkDomainToLdapResponse response = new LinkDomainToLdapResponse(domainId, type, name, (short)accountType) | ||||
|         _ldapManager.linkDomainToLdap(_,_,_,_) >> response | ||||
|         _ldapManager.getUser(username, type, name) >> new LdapUser(username, "admin@ccp.citrix.com", "Admin", "Admin", name, "ccp", false) | ||||
| 
 | ||||
|         _accountService.getActiveAccountByName(username, domainId) >> null | ||||
|         UserAccount userAccount = Mock(UserAccount) | ||||
|         userAccount.getAccountId() >> 24 | ||||
|         _accountService.createUserAccount(username, "", "Admin", "Admin", "admin@ccp.citrix.com", null, username, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, domainId, | ||||
|                 username, null, _, _, User.Source.LDAP) >> { throw new RuntimeException("created failed from mock") } | ||||
| 
 | ||||
|         linkDomainToLdapCmd.admin = username | ||||
|         linkDomainToLdapCmd.type = type | ||||
|         linkDomainToLdapCmd.name = name | ||||
|         linkDomainToLdapCmd.domainId = domainId | ||||
| 
 | ||||
|         when: | ||||
|         linkDomainToLdapCmd.execute() | ||||
|         then: | ||||
|         LinkDomainToLdapResponse result = (LinkDomainToLdapResponse)linkDomainToLdapCmd.getResponseObject() | ||||
|         result.getObjectName() == "LinkDomainToLdap" | ||||
|         result.getResponseName() == linkDomainToLdapCmd.getCommandName() | ||||
|         result.getDomainId() == domainId | ||||
|         result.getType() == type | ||||
|         result.getName() == name | ||||
|         result.getAdminId() == null | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -2145,14 +2145,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M | ||||
|             s_logger.debug("Attempting to log in user: " + username + " in domain " + domainId); | ||||
|         } | ||||
|         UserAccount userAccount = _userAccountDao.getUserAccount(username, domainId); | ||||
|         if (userAccount == null) { | ||||
|             s_logger.warn("Unable to find an user with username " + username + " in domain " + domainId); | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         boolean authenticated = false; | ||||
|         HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<ActionOnFailedAuthentication>(); | ||||
|         User.Source userSource = userAccount.getSource(); | ||||
|         User.Source userSource = userAccount != null ? userAccount.getSource(): User.Source.UNKNOWN; | ||||
|         for (UserAuthenticator authenticator : _userAuthenticators) { | ||||
|             if(userSource != User.Source.UNKNOWN) { | ||||
|                 if(!authenticator.getName().equalsIgnoreCase(userSource.name())){ | ||||
| @ -2177,6 +2173,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M | ||||
|             if (domain != null) { | ||||
|                 domainName = domain.getName(); | ||||
|             } | ||||
|             userAccount = _userAccountDao.getUserAccount(username, domainId); | ||||
| 
 | ||||
|             if (!userAccount.getState().equalsIgnoreCase(Account.State.enabled.toString()) || | ||||
|                 !userAccount.getAccountState().equalsIgnoreCase(Account.State.enabled.toString())) { | ||||
| @ -2196,6 +2193,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M | ||||
|                 s_logger.debug("Unable to authenticate user with username " + username + " in domain " + domainId); | ||||
|             } | ||||
| 
 | ||||
|             if (userAccount == null) { | ||||
|                 s_logger.warn("Unable to find an user with username " + username + " in domain " + domainId); | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             if (userAccount.getState().equalsIgnoreCase(Account.State.enabled.toString())) { | ||||
|                 if (!isInternalAccount(userAccount.getId())) { | ||||
|                     // Internal accounts are not disabled | ||||
|  | ||||
| @ -399,3 +399,13 @@ CREATE TABLE `cloud`.`external_bigswitch_bcf_devices` ( | ||||
|   CONSTRAINT `fk_external_bigswitch_bcf_devices__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE | ||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; | ||||
| 
 | ||||
| CREATE TABLE `cloud`.`ldap_trust_map` ( | ||||
|   `id` int unsigned NOT NULL AUTO_INCREMENT, | ||||
|   `domain_id` bigint unsigned NOT NULL, | ||||
|   `type` varchar(10) NOT NULL, | ||||
|   `name` varchar(255) NOT NULL, | ||||
|   `account_type` int(1) unsigned NOT NULL, | ||||
|   PRIMARY KEY (`id`), | ||||
|   UNIQUE KEY `uk_ldap_trust_map__domain_id` (`domain_id`), | ||||
|   CONSTRAINT `fk_ldap_trust_map__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain` (`id`) | ||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; | ||||
|  | ||||
| @ -12853,6 +12853,14 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it | ||||
|   background-position: -230px -677px; | ||||
| } | ||||
| 
 | ||||
| .linktoldap .icon { | ||||
|   background-position: -197px -65px; | ||||
| } | ||||
| 
 | ||||
| .linktoldap:hover .icon { | ||||
|   background-position: -197px -647px; | ||||
| } | ||||
| 
 | ||||
| .label-hovered { | ||||
|   cursor: pointer; | ||||
|   color: #0000FF !important; | ||||
|  | ||||
| @ -1066,6 +1066,10 @@ under the License. | ||||
| 'label.ovm3.vip': '<fmt:message key="label.ovm3.vip" />', | ||||
| 'label.local.file': '<fmt:message key="label.local.file" />', | ||||
| 'label.local.storage.enabled.system.vms': '<fmt:message key="label.local.storage.enabled.system.vms" />', | ||||
| 'label.link.domain.to.ldap': '<fmt:message key="label.link.domain.to.ldap" />', | ||||
| 'message.link.domain.to.ldap': '<fmt:message key="message.link.domain.to.ldap" />', | ||||
| 'label.ldap.link.type': '<fmt:message key="label.ldap.link.type" />', | ||||
| 'label.account.type': '<fmt:message key="label.account.type" />' | ||||
| 'label.create.ssh.key.pair': '<fmt:message key="label.create.ssh.key.pair" />', | ||||
| 'label.fingerprint': '<fmt:message key="label.fingerprint" />', | ||||
| 'label.host.tag': '<fmt:message key="label.host.tag" />', | ||||
|  | ||||
| @ -1317,5 +1317,16 @@ cloudStack.docs = { | ||||
|     helpOvm3Vip: { | ||||
|         desc: 'The VIP used by the pool and cluster', | ||||
|         externalLink: '' | ||||
|     }, | ||||
|     helpLdapGroupName: { | ||||
|         desc: 'Fully qualified name of OU/GROUP in LDAP', | ||||
|         externalLink: '' | ||||
|     }, | ||||
|     helpLdapGroupType: { | ||||
|         desc: 'Type of LDAP name provided. Can be either GROUP/OU', | ||||
|         externalLink: '' | ||||
|     }, | ||||
|     helpLdapLinkDomainAdmin: { | ||||
|         desc: 'domain admin of the linked domain. Specify a username in GROUP/OU of LDAP' | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @ -313,6 +313,109 @@ | ||||
|                         } | ||||
|                     }, | ||||
| 
 | ||||
|                     linktoldap: { | ||||
|                             label: 'label.link.domain.to.ldap', | ||||
| 
 | ||||
|                             action: function(args) { | ||||
|                                 var data = { | ||||
|                                     domainid: args.context.domains[0].id, | ||||
|                                     type: args.data.type, | ||||
|                                     name: args.data.name, | ||||
|                                     accounttype: args.data.accounttype | ||||
|                                 }; | ||||
| 
 | ||||
|                                 if (args.data.admin != null && args.data.admin.length > 0) { | ||||
|                                     $.extend(data, { | ||||
|                                         admin: args.data.admin | ||||
|                                     }); | ||||
|                                 } | ||||
| 
 | ||||
|                                 $.ajax({ | ||||
|                                     url: createURL('linkDomainToLdap'), | ||||
|                                     data: data, | ||||
|                                     success: function(json) { | ||||
|                                         var item = json.linkdomaintoldapresponse.LinkDomainToLdap.domainid; | ||||
|                                         args.response.success({ | ||||
|                                             data: item | ||||
|                                         }); | ||||
|                                     }, | ||||
|                                     error: function(XMLHttpResponse) { | ||||
|                                         var errorMsg = parseXMLHttpResponse(XMLHttpResponse); | ||||
|                                         args.response.error(errorMsg); | ||||
|                                     } | ||||
|                                 }); | ||||
|                             }, | ||||
| 
 | ||||
|                             messages: { | ||||
|                                 notification: function(args) { | ||||
|                                     return 'label.link.domain.to.ldap'; | ||||
|                                 } | ||||
|                             }, | ||||
| 
 | ||||
|                             createForm: { | ||||
|                                 title: 'label.link.domain.to.ldap', | ||||
|                                 desc: 'message.link.domain.to.ldap', | ||||
|                                 fields: { | ||||
|                                     type: { | ||||
|                                         label: 'label.ldap.link.type', | ||||
|                                         docID: 'helpLdapGroupType', | ||||
|                                         validation: { | ||||
|                                             required: true | ||||
|                                         }, | ||||
|                                         select: function(args) { | ||||
|                                              var items = []; | ||||
|                                              items.push({ | ||||
|                                                  id: "GROUP", | ||||
|                                                  description: "GROUP" | ||||
|                                              }); //regular-user
 | ||||
|                                              items.push({ | ||||
|                                                  id: "OU", | ||||
|                                                  description: "OU" | ||||
|                                              }); //root-admin
 | ||||
|                                              args.response.success({ | ||||
|                                                  data: items | ||||
|                                              }); | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     name: { | ||||
|                                         label: 'label.name', | ||||
|                                         docID: 'helpLdapGroupName', | ||||
|                                         validation: { | ||||
|                                             required: true | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     accounttype: { | ||||
|                                         label: 'label.account.type', | ||||
|                                         docID: 'helpAccountType', | ||||
|                                         validation: { | ||||
|                                             required: true | ||||
|                                         }, | ||||
|                                         select: function(args) { | ||||
|                                              var items = []; | ||||
|                                              items.push({ | ||||
|                                                  id: 0, | ||||
|                                                  description: "Normal User" | ||||
|                                              }); //regular-user
 | ||||
|                                              items.push({ | ||||
|                                                  id: 2, | ||||
|                                                  description: "Domain Admin" | ||||
|                                              }); //root-admin
 | ||||
|                                              args.response.success({ | ||||
|                                                  data: items | ||||
|                                              }); | ||||
|                                         } | ||||
|                                     }, | ||||
|                                     admin: { | ||||
|                                         label: 'label.domain.admin', | ||||
|                                         docID: 'helpLdapLinkDomainAdmin', | ||||
|                                         validation: { | ||||
|                                             required: false | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                     }, | ||||
| 
 | ||||
|                     updateResourceCount: { | ||||
|                         label: 'label.action.update.resource.count', | ||||
|                         messages: { | ||||
| @ -652,6 +755,9 @@ | ||||
|             if (jsonObj.level != 0) { //ROOT domain (whose level is 0) is not allowed to delete
 | ||||
|                 allowedActions.push("delete"); | ||||
|             } | ||||
|             if(isLdapEnabled()) { | ||||
|                 allowedActions.push("linktoldap") | ||||
|             } | ||||
|         } else if (isDomainAdmin()) { | ||||
|             if (args.context.domains[0].id != g_domainid) { | ||||
|                 allowedActions.push("edit"); //merge updateResourceLimit into edit
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user