blob: 880ecea4d13ca13c0ebbb05947f30d6283e6eb3b [file] [log] [blame]
// 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 com.cloud.domain.DomainVO;
import com.cloud.user.Account;
import com.cloud.user.AccountService;
import com.cloud.user.User;
import com.cloud.user.UserAccount;
import org.apache.cloudstack.acl.RoleType;
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.ResponseObject.ResponseView;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.RoleResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.ldap.LdapManager;
import org.apache.cloudstack.ldap.LdapUser;
import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
import org.bouncycastle.util.encoders.Base64;
import javax.inject.Inject;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Map;
@APICommand(name = "ldapCreateAccount", description = "Creates an account from an LDAP user", responseObject = AccountResponse.class, since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class LdapCreateAccountCmd extends BaseCmd {
private static final String s_name = "createaccountresponse";
@Inject
private LdapManager _ldapManager;
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "Creates the user under the specified account. If no account is specified, the username will be used as the account name.")
private String accountName;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.INTEGER, description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin")
private Integer accountType;
@Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.")
private Long roleId;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Creates the user under the specified domain.")
private Long domainId;
@Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
private String timezone;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Unique username.")
private String username;
@Parameter(name = ApiConstants.NETWORK_DOMAIN, type = CommandType.STRING, description = "Network domain for the account's networks")
private String networkDomain;
@Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters")
private Map<String, String> details;
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.STRING, description = "Account UUID, required for adding account from external provisioning system")
private String accountUUID;
@Parameter(name = ApiConstants.USER_ID, type = CommandType.STRING, description = "User UUID, required for adding account from external provisioning system")
private String userUUID;
public LdapCreateAccountCmd() {
super();
}
public LdapCreateAccountCmd(final LdapManager ldapManager, final AccountService accountService) {
super();
_ldapManager = ldapManager;
_accountService = accountService;
}
UserAccount createCloudstackUserAccount(final LdapUser user, String accountName, Long domainId) {
Account account = _accountService.getActiveAccountByName(accountName, domainId);
if (account == null) {
return _accountService.createUserAccount(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, getAccountType(), getRoleId(),
domainId, networkDomain, details, accountUUID, userUUID, User.Source.LDAP);
} else {
User newUser = _accountService.createUser(username, generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domainId,
userUUID, User.Source.LDAP);
return _accountService.getUserAccountById(newUser.getId());
}
}
public Account.Type getAccountType() {
if (accountType == null) {
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), null);
}
return RoleType.getAccountTypeByRole(roleService.findRole(roleId), Account.Type.getFromValue(accountType.intValue()));
}
public Long getRoleId() {
return RoleType.getRoleByAccountType(roleId, getAccountType());
}
private String getAccountName() {
String name = accountName;
if (accountName == null) {
name = username;
}
return name;
}
private Long getDomainId() {
Long id = domainId;
if (id == null) {
id = DomainVO.ROOT_DOMAIN;
}
return id;
}
@Override
public void execute() throws ServerApiException {
if (getAccountType() == null && getRoleId() == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided");
}
final CallContext callContext = getCurrentContext();
String finalAccountName = getAccountName();
Long finalDomainId = getDomainId();
callContext.setEventDetails("Account Name: " + finalAccountName + ", Domain Id:" + finalDomainId);
try {
final LdapUser user = _ldapManager.getUser(username, domainId);
validateUser(user);
final UserAccount userAccount = createCloudstackUserAccount(user, finalAccountName, finalDomainId);
if (userAccount != null) {
final AccountResponse response = _responseGenerator.createUserAccountResponse(ResponseView.Full, userAccount);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create a user account");
}
} catch (NoLdapUserMatchingQueryException e) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "No LDAP user exists with the username of " + username);
}
}
private String generatePassword() throws ServerApiException {
try {
final SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
final byte bytes[] = new byte[20];
randomGen.nextBytes(bytes);
return new String(Base64.encode(bytes), "UTF-8");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password");
}
}
@Override
public String getCommandName() {
return s_name;
}
CallContext getCurrentContext() {
return CallContext.current();
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
private boolean validateUser(final LdapUser user) throws ServerApiException {
if (user.getEmail() == null) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username + " has no email address set within LDAP");
}
if (user.getFirstname() == null) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username + " has no firstname set within LDAP");
}
if (user.getLastname() == null) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, username + " has no lastname set within LDAP");
}
return true;
}
}