diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 959a710d6d9..9683d9fa330 100644 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; import com.cloud.domain.Domain; @@ -28,6 +29,7 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; + public interface AccountService { /** @@ -124,6 +126,8 @@ public interface AccountService { void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException; + void checkAccess(User user, ControlledEntity entity); + void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException; @@ -136,4 +140,5 @@ public interface AccountService { */ UserAccount getUserAccountById(Long userId); + public Map getKeys(GetUserKeysCmd cmd); } diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java new file mode 100644 index 00000000000..f93c6e11728 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/user/GetUserKeysCmd.java @@ -0,0 +1,77 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.admin.user; + + +import com.cloud.user.Account; +import com.cloud.user.User; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.RegisterResponse; +import org.apache.cloudstack.api.response.UserResponse; + +import java.util.Map; +import java.util.logging.Logger; + +@APICommand(name = GetUserKeysCmd.APINAME, + description = "This command allows the user to query the seceret and API keys for the account", + responseObject = RegisterResponse.class, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = true, + authorized = {RoleType.User, RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin}, + since = "4.10.0") + +public class GetUserKeysCmd extends BaseCmd{ + + @Parameter(name= ApiConstants.ID, type = CommandType.UUID, entityType = UserResponse.class, required = true, description = "ID of the user whose keys are required") + private Long id; + + public static final Logger s_logger = Logger.getLogger(RegisterCmd.class.getName()); + public static final String APINAME = "getUserKeys"; + + public Long getID(){ + return id; + } + + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + public long getEntityOwnerId(){ + User user = _entityMgr.findById(User.class, getID()); + if(user != null){ + return user.getAccountId(); + } + else return Account.ACCOUNT_ID_SYSTEM; + } + public void execute(){ + Map keys = _accountService.getKeys(this); + RegisterResponse response = new RegisterResponse(); + if(keys != null){ + response.setApiKey(keys.get("apikey")); + response.setSecretKey(keys.get("secretkey")); + } + + response.setObjectName("userkeys"); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/response/UserResponse.java b/api/src/org/apache/cloudstack/api/response/UserResponse.java index cc986b38a1c..d96f632f1a3 100644 --- a/api/src/org/apache/cloudstack/api/response/UserResponse.java +++ b/api/src/org/apache/cloudstack/api/response/UserResponse.java @@ -94,6 +94,7 @@ public class UserResponse extends BaseResponse { @Param(description = "the api key of the user", isSensitive = true) private String apiKey; + @Deprecated @SerializedName("secretkey") @Param(description = "the secret key of the user", isSensitive = true) private String secretKey; @@ -236,7 +237,6 @@ public class UserResponse extends BaseResponse { public String getSecretKey() { return secretKey; } - public void setSecretKey(String secretKey) { this.secretKey = secretKey; } diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java index e56766aaf46..a6170131292 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/MockAccountManager.java @@ -24,6 +24,8 @@ import java.net.InetAddress; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.log4j.Logger; import org.apache.cloudstack.acl.ControlledEntity; @@ -432,4 +434,24 @@ public class MockAccountManager extends ManagerBase implements AccountManager { public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { // TODO Auto-generated method stub } + + @Override + public Map getKeys(GetUserKeysCmd cmd){ + return null; + } + + @Override + public void checkAccess(User user, ControlledEntity entity) + throws PermissionDeniedException { + + } + @Override + public String getConfigComponentName() { + return null; + } + + @Override + public ConfigKey[] getConfigKeys() { + return null; + } } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 5c5abc99bfe..a3e0439a0a0 100644 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -310,6 +310,7 @@ import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.dao.VMSnapshotDao; +import com.cloud.user.AccountManager; public class ApiDBUtils { private static ManagementServer s_ms; @@ -1710,6 +1711,9 @@ public class ApiDBUtils { public static UserResponse newUserResponse(UserAccountJoinVO usr, Long domainId) { UserResponse response = s_userAccountJoinDao.newUserResponse(usr); + if(!AccountManager.UseSecretKeyInResponse.value()){ + response.setSecretKey(null); + } // Populate user account role information if (usr.getAccountRoleId() != null) { Role role = s_roleService.findRole( usr.getAccountRoleId()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 3b9125ca494..c20039abd81 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -220,6 +220,7 @@ import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; import org.apache.cloudstack.api.command.admin.user.GetUserCmd; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; import org.apache.cloudstack.api.command.admin.user.LockUserCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; @@ -3016,6 +3017,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(ConfigureOutOfBandManagementCmd.class); cmdList.add(IssueOutOfBandManagementPowerActionCmd.class); cmdList.add(ChangeOutOfBandManagementPasswordCmd.class); + cmdList.add(GetUserKeysCmd.class); return cmdList; } diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 9789a223296..9e0dde20868 100644 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -33,12 +33,14 @@ import com.cloud.utils.Pair; import com.cloud.utils.Ternary; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; /** * AccountManager includes logic that deals with accounts, domains, and users. * */ -public interface AccountManager extends AccountService { +public interface AccountManager extends AccountService, Configurable{ /** * Disables an account by accountId * @param accountId @@ -198,4 +200,11 @@ public interface AccountManager extends AccountService { public static final String MESSAGE_ADD_ACCOUNT_EVENT = "Message.AddAccount.Event"; public static final String MESSAGE_REMOVE_ACCOUNT_EVENT = "Message.RemoveAccount.Event"; + public static final ConfigKey UseSecretKeyInResponse = new ConfigKey( + "Advanced", + Boolean.class, + "use.secret.key.in.response", + "false", + "This parameter allows the users to enable or disable of showing secret key as a part of response for various APIs. By default it is set to false.", + true); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 1a3607f1f3f..45768cf3c6e 100644 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -16,52 +16,6 @@ // under the License. package com.cloud.user; -import java.net.InetAddress; -import java.net.URLEncoder; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.acl.QuerySelector; -import org.apache.cloudstack.acl.RoleType; -import org.apache.cloudstack.acl.SecurityChecker; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.affinity.AffinityGroup; -import org.apache.cloudstack.affinity.dao.AffinityGroupDao; -import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; -import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; -import org.apache.cloudstack.api.command.admin.user.RegisterCmd; -import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.framework.messagebus.MessageBus; -import org.apache.cloudstack.framework.messagebus.PublishScope; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao; -import org.apache.cloudstack.utils.baremetal.BaremetalUtils; - import com.cloud.api.ApiDBUtils; import com.cloud.api.query.vo.ControlledViewEntity; import com.cloud.configuration.Config; @@ -168,6 +122,53 @@ import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.QuerySelector; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.affinity.AffinityGroup; +import org.apache.cloudstack.affinity.dao.AffinityGroupDao; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; +import org.apache.cloudstack.api.command.admin.user.RegisterCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao; +import org.apache.cloudstack.utils.baremetal.BaremetalUtils; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + + public class AccountManagerImpl extends ManagerBase implements AccountManager, Manager { public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class); @@ -1363,10 +1364,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M boolean success = Transaction.execute(new TransactionCallback() { @Override public Boolean doInTransaction(TransactionStatus status) { - boolean success = doSetUserStatus(userId, State.enabled); + boolean success = doSetUserStatus(userId, State.enabled); - // make sure the account is enabled too - success = success && enableAccount(user.getAccountId()); + // make sure the account is enabled too + success = success && enableAccount(user.getAccountId()); return success; } @@ -2220,6 +2221,24 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M return _accountDao.findUserAccountByApiKey(apiKey); } + @Override + public Map getKeys(GetUserKeysCmd cmd){ + final long userId = cmd.getID(); + + User user = getActiveUser(userId); + if(user==null){ + throw new InvalidParameterValueException("Unable to find user by id"); + } + final ControlledEntity account = getAccount(getUserAccountById(userId).getAccountId()); //Extracting the Account from the userID of the requested user. + checkAccess(CallContext.current().getCallingUser(), account); + + Map keys = new HashMap(); + keys.put("apikey", user.getApiKey()); + keys.put("secretkey", user.getSecretKey()); + + return keys; + } + @Override @DB @ActionEvent(eventType = EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY, eventDescription = "register for the developer API keys") @@ -2632,4 +2651,28 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M assert false : "How can all of the security checkers pass on checking this caller?"; throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + dof); } + + @Override + public void checkAccess(User user, ControlledEntity entity) + throws PermissionDeniedException { + for(SecurityChecker checker : _securityCheckers){ + if(checker.checkAccess(user,entity)){ + if(s_logger.isDebugEnabled()){ + s_logger.debug("Access granted to " + user + "to " + entity + "by " + checker.getName()); + } + return; + } + } + throw new PermissionDeniedException("There's no way to confirm " + user + " has access to " + entity); + } + + @Override + public String getConfigComponentName() { + return AccountManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[]{UseSecretKeyInResponse}; + } } diff --git a/server/test/com/cloud/user/AccountManagerImplTest.java b/server/test/com/cloud/user/AccountManagerImplTest.java index 278804962f8..a4da8191e33 100644 --- a/server/test/com/cloud/user/AccountManagerImplTest.java +++ b/server/test/com/cloud/user/AccountManagerImplTest.java @@ -20,9 +20,14 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; + +import com.cloud.acl.DomainChecker; +import com.cloud.exception.PermissionDeniedException; import com.cloud.server.auth.UserAuthenticator; import com.cloud.utils.Pair; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; +import org.apache.cloudstack.context.CallContext; import org.junit.Assert; import org.junit.Test; import org.mockito.Mock; @@ -170,5 +175,38 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase { Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null); } + @Mock + AccountVO callingAccount; + @Mock + DomainChecker domainChecker; + @Mock + AccountService accountService; + @Mock + private GetUserKeysCmd _listkeyscmd; + @Mock + private Account _account; + @Mock + private User _user; + @Mock + private UserAccountVO userAccountVO; + + @Test (expected = PermissionDeniedException.class) + public void testgetUserCmd(){ + CallContext.register(callingUser, callingAccount); // Calling account is user account i.e normal account + Mockito.when(_listkeyscmd.getID()).thenReturn(1L); + Mockito.when(accountManager.getActiveUser(1L)).thenReturn(_user); + Mockito.when(accountManager.getUserAccountById(1L)).thenReturn(userAccountVO); + Mockito.when(userAccountVO.getAccountId()).thenReturn(1L); + Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(_account); // Queried account - admin account + + Mockito.when(callingUser.getAccountId()).thenReturn(1L); + Mockito.when(_accountDao.findById(1L)).thenReturn(callingAccount); + + Mockito.when(accountService.isNormalUser(Mockito.anyLong())).thenReturn(Boolean.TRUE); + Mockito.when(_account.getAccountId()).thenReturn(2L); + + accountManager.getKeys(_listkeyscmd); + + } } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index fd851672255..9429c86a117 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -22,6 +22,8 @@ import java.net.InetAddress; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; +import org.apache.cloudstack.framework.config.ConfigKey; import org.springframework.stereotype.Component; import org.apache.cloudstack.acl.ControlledEntity; @@ -401,5 +403,24 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco return null; } + @Override + public Map getKeys(GetUserKeysCmd cmd) { + return null; + } + + @Override + public void checkAccess(User user, ControlledEntity entity) + throws PermissionDeniedException { + + } + @Override + public String getConfigComponentName() { + return null; + } + + @Override + public ConfigKey[] getConfigKeys() { + return null; + } } diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index ce7ffc9b509..08b3f348c75 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -147,9 +147,19 @@ class CSTestClient(object): self.__logger.error("__createApiClient: API " "Client Creation Failed") return FAILED + + getuser_keys = getUserKeys.getUserKeysCmd() + getuser_keys.id = list_user_res[0].id + getuser_keys_res = self.__apiClient.getUserKeys(getuser_keys) + if getuser_keys_res is None : + self.__logger.error("__createApiClient: API " + "Client Creation Failed") + return FAILED + + api_key = getuser_keys_res.apikey + security_key = getuser_keys_res.secretkey + user_id = list_user_res[0].id - api_key = list_user_res[0].apikey - security_key = list_user_res[0].secretkey if api_key is None: ret = self.__getKeys(user_id) if ret != FAILED: @@ -210,7 +220,18 @@ class CSTestClient(object): self.__apiClient.registerUserKeys(register_user) if not register_user_res: return FAILED - return (register_user_res.apikey, register_user_res.secretkey) + + getuser_keys = getUserKeys.getUserKeysCmd() + getuser_keys.id = userid + getuser_keys_res = self.__apiClient.getUserKeys(getuser_keys) + if getuser_keys_res is None : + self.__logger.error("__createApiClient: API " + "Client Creation Failed") + return FAILED + + api_key = getuser_keys_res.apikey + security_key = getuser_keys_res.secretkey + return (api_key, security_key) except Exception as e: self.__logger.exception("Exception Occurred Under __geKeys : " "%s" % GetDetailExceptionInfo(e)) @@ -349,8 +370,17 @@ class CSTestClient(object): listuserRes = self.__apiClient.listUsers(listuser) userId = listuserRes[0].id - apiKey = listuserRes[0].apikey - securityKey = listuserRes[0].secretkey + + getuser_keys = getUserKeys.getUserKeysCmd() + getuser_keys.id = listuserRes[0].id + getuser_keys_res = self.__apiClient.getUserKeys(getuser_keys) + if getuser_keys_res is None or\ + (validateList(getuser_keys_res) != PASS): + self.__logger.error("__createApiClient: API " + "Client Creation Failed") + + apiKey = getuser_keys_res.apikey + securityKey = getuser_keys_res.secretkey if apiKey is None: ret = self.__getKeys(userId) diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js index 913f81ff516..4488fdcc9cd 100644 --- a/ui/scripts/accounts.js +++ b/ui/scripts/accounts.js @@ -1638,20 +1638,33 @@ }], dataProvider: function(args) { - if (isAdmin() || isDomainAdmin()) { - $.ajax({ - url: createURL('listUsers'), + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listUsers'), data: { id: args.context.users[0].id }, success: function(json) { - args.response.success({ - actionFilter: userActionfilter, - data: json.listusersresponse.user[0] - }); - } - }); - } else { //normal user doesn't have access listUsers API until Bug 14127 is fixed. + var items = json.listusersresponse.user[0]; + $.ajax({ + url: createURL('getUserKeys'),//change + data: { + id: args.context.users[0].id//change + }, + success: function(json) { + $.extend(items, { + secretkey: json.getuserkeysresponse.userkeys.secretkey//change + }); + args.response.success({ + actionFilter: userActionfilter, + data: items + }); + } + }); + } + }); + } + else { //normal user doesn't have access listUsers API until Bug 14127 is fixed. args.response.success({ actionFilter: userActionfilter, data: args.context.users[0]