Last active
December 1, 2020 11:27
-
-
Save ichengchao/56c8314b83497ec4d86e6cff01b42c0f to your computer and use it in GitHub Desktop.
账号生成逻辑. web: tools.html controller:AliyunToolsController.java service: ResourceDirectoryAccountFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package name.chengchao.springrun.controller; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import name.chengchao.springrun.model.WebResult; | |
import name.chengchao.springrun.sso.tools.ResourceDirectoryAccountFactory; | |
import name.chengchao.springrun.util.UUIDUtils; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
@Controller | |
@RequestMapping("/aliyunTools") | |
public class AliyunToolsController extends BaseController { | |
@RequestMapping("/createAccount") | |
public void createAccount(HttpServletRequest request, HttpServletResponse response) { | |
WebResult result = new WebResult(); | |
try { | |
final String accessKeyId = request.getParameter("accessKeyId"); | |
final String accessKeySecret = request.getParameter("accessKeySecret"); | |
final String email = request.getParameter("email"); | |
final String id = UUIDUtils.generateUUID(); | |
ResourceDirectoryAccountFactory.logMap.put(id, new StringBuilder()); | |
new Thread(new Runnable() { | |
@Override | |
public void run() { | |
try { | |
ResourceDirectoryAccountFactory.buildNewRD(accessKeyId, accessKeySecret, email, id); | |
} catch (Exception e) { | |
logger.error(e.getMessage(), e); | |
} | |
} | |
}).start(); | |
result.setData(id); | |
} catch (Exception e) { | |
logger.error(e.getMessage(), e); | |
result.setSuccess(false); | |
result.setErrorMsg(e.getMessage()); | |
} | |
outputToJSON(response, result); | |
} | |
@RequestMapping("/getProcessById") | |
public void getProcessById(HttpServletRequest request, HttpServletResponse response) { | |
WebResult result = new WebResult(); | |
try { | |
String id = request.getParameter("id"); | |
if (null == ResourceDirectoryAccountFactory.logMap.get(id)) { | |
result.setData("can not find log,id:" + id); | |
} else { | |
String log = ResourceDirectoryAccountFactory.logMap.get(id).toString(); | |
result.setData(log); | |
} | |
} catch (Exception e) { | |
logger.error(e.getMessage(), e); | |
result.setSuccess(false); | |
result.setErrorMsg(e.getMessage()); | |
} | |
outputToJSON(response, result); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package name.chengchao.springrun.sso.tools; | |
import java.util.HashMap; | |
import java.util.Map; | |
import com.alibaba.fastjson.JSON; | |
import com.aliyuncs.CommonRequest; | |
import com.aliyuncs.CommonResponse; | |
import com.aliyuncs.DefaultAcsClient; | |
import com.aliyuncs.IAcsClient; | |
import com.aliyuncs.auth.BasicCredentials; | |
import com.aliyuncs.auth.STSAssumeRoleSessionCredentialsProvider; | |
import com.aliyuncs.exceptions.ClientException; | |
import com.aliyuncs.http.ProtocolType; | |
import com.aliyuncs.profile.DefaultProfile; | |
import name.chengchao.springrun.util.UUIDUtils; | |
import org.apache.commons.lang3.RandomStringUtils; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* 利用已认证主体的账号生成新账号,并且开通RD,成为新RD的Master,并把原来账号邀请进来 | |
*/ | |
public class ResourceDirectoryAccountFactory { | |
public static final Map<String, StringBuilder> logMap = new HashMap<>(); | |
public static final ThreadLocal<String> ctx = new ThreadLocal<>(); | |
public static final Logger logger = LoggerFactory.getLogger(ResourceDirectoryAccountFactory.class); | |
public static void main(String[] args) { | |
} | |
public static void loggerInfo(String msg) { | |
logger.info(msg); | |
String traceId = ctx.get(); | |
StringBuilder sb = logMap.get(traceId); | |
sb.append("<br/>"); | |
sb.append(msg); | |
} | |
public static void buildNewRD(String masterAccountAccessKeyId, String masterAccountAccessKeySecret, String email, String traceId) throws Exception { | |
ctx.set(traceId); | |
DefaultProfile AliyunProfile = DefaultProfile.getProfile("cn-hangzhou"); | |
IAcsClient masterClient = new DefaultAcsClient(AliyunProfile, new BasicCredentials(masterAccountAccessKeyId, masterAccountAccessKeySecret)); | |
//1. 初始化RD | |
String rdInfo = GetResourceDirectory(masterClient); | |
if (null != rdInfo) { | |
int count = ListAccounts(masterClient); | |
if (count > 0) { | |
loggerInfo("this account has sub account,rdinfo:" + rdInfo); | |
return; | |
} | |
} else { | |
//如果rdInfo为null,则表示该账号没有开通过RD | |
initResourceDirectory(masterClient); | |
} | |
//2. 创建成员账号,继承主体认证 | |
rdInfo = GetResourceDirectory(masterClient); | |
String rootFolderId = JSON.parseObject(rdInfo).getJSONObject("ResourceDirectory").getString("RootFolderId"); | |
String createResult = CreateResourceAccount(masterClient, "langingzone_" + UUIDUtils.generateUUID(), rootFolderId); | |
String accountId = JSON.parseObject(createResult).getJSONObject("Account").getString("AccountId"); | |
PromoteResourceAccount(masterClient, accountId, email); | |
boolean confirmEmail = false; | |
//3. 等待用户点击"立即确认"按钮 | |
for (int i = 0; i < 60; i++) { | |
Thread.sleep(10000); | |
String accountInfo = GetAccount(masterClient, accountId); | |
String accountType = JSON.parseObject(accountInfo).getJSONObject("Account").getString("Type"); | |
if ("CloudAccount".equals(accountType)) { | |
confirmEmail = true; | |
break; | |
} | |
loggerInfo("waiting confirm email,accountId:" + accountId); | |
} | |
if (!confirmEmail) { | |
loggerInfo("reach max waiting count,exit!"); | |
return; | |
} | |
//4. 获取新账号的ram user的AK | |
//4.1 先换出master账号的ram user 的AK | |
String callerIdentity = GetCallerIdentity(masterClient); | |
String masterAccountId = JSON.parseObject(callerIdentity).getString("AccountId"); | |
String masterRamUserName = "landingzone_master_" + UUIDUtils.generateUUID(); | |
Map<String, String> masterRamUserAKMap = CreateRamUserAccessKey(masterClient, masterAccountId, masterRamUserName); | |
STSAssumeRoleSessionCredentialsProvider provider = new STSAssumeRoleSessionCredentialsProvider(new BasicCredentials(masterRamUserAKMap.get("AccessKeyId"), masterRamUserAKMap.get("AccessKeySecret")), "acs:ram::" + accountId + ":role/resourcedirectoryaccountaccessrole", AliyunProfile); | |
DefaultAcsClient assumeRoleClient = new DefaultAcsClient(AliyunProfile, provider); | |
//4.2 换取目标账户ram user的AK | |
String subRamUserName = "masteradmin"; | |
Map<String, String> subRamUserAKMap = CreateRamUserAccessKey(assumeRoleClient, accountId, subRamUserName); | |
String subRamUserPassword = RandomStringUtils.randomAlphanumeric(10); | |
CreateLoginProfile(assumeRoleClient, subRamUserName, subRamUserPassword); | |
IAcsClient newAccountRamUserClient = new DefaultAcsClient(AliyunProfile, new BasicCredentials(subRamUserAKMap.get("AccessKeyId"), subRamUserAKMap.get("AccessKeySecret"))); | |
//4.3 清理主账号的ram user | |
DeleteUser(masterClient, masterRamUserName, masterRamUserAKMap.get("AccessKeyId"), true); | |
//5. 解绑账号 | |
RemoveCloudAccount(masterClient, accountId); | |
//6. 开通RD | |
initResourceDirectory(newAccountRamUserClient); | |
//7. 关闭原来的账号RD | |
DestroyResourceDirectory(masterClient); | |
//8. 用新账号邀请原来账号进入RD | |
String inviteResult = InviteAccountToResourceDirectory(newAccountRamUserClient, masterAccountId); | |
String handshakeId = JSON.parseObject(inviteResult).getJSONObject("Handshake").getString("HandshakeId"); | |
Thread.sleep(3000); | |
AcceptHandshake(masterClient, handshakeId); | |
//9. 清理新账号的ram user,由于循环问题不删除user,只清理改user的policy 和 ak | |
DeleteUser(newAccountRamUserClient, subRamUserName, subRamUserAKMap.get("AccessKeyId"), false); | |
loggerInfo("*******************************************************************"); | |
loggerInfo("master account: " + email); | |
loggerInfo("-------------------------------------------------------------------"); | |
loggerInfo("ram user name: " + subRamUserName); | |
loggerInfo("ram user passowrd: " + subRamUserPassword); | |
loggerInfo("ram user login url: "); | |
loggerInfo("https://signin.aliyun.com/" + accountId + ".onaliyun.com/login.htm?callback=https%3A%2F%2Fhomenew.console.aliyun.com%2F#/login"); | |
loggerInfo("*******************************************************************"); | |
loggerInfo("__done__"); | |
} | |
public static Map<String, String> CreateRamUserAccessKey(IAcsClient client, String accountId, String ramUserName) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
CommonResponse response; | |
//CreateUser | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("CreateUser"); | |
request.putQueryParameter("UserName", ramUserName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][CreateUser]:" + response.getData()); | |
//AttachPolicyToUser | |
request = new CommonRequest(); | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("AttachPolicyToUser"); | |
request.putQueryParameter("PolicyType", "System"); | |
request.putQueryParameter("PolicyName", "AdministratorAccess"); | |
request.putQueryParameter("UserName", ramUserName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][AttachPolicyToUser]:" + response.getData()); | |
//CreateAccessKey | |
request = new CommonRequest(); | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("CreateAccessKey"); | |
request.putQueryParameter("UserName", ramUserName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][CreateAccessKey]:" + response.getData()); | |
String AccessKeyId = JSON.parseObject(response.getData()).getJSONObject("AccessKey").getString("AccessKeyId"); | |
String AccessKeySecret = JSON.parseObject(response.getData()).getJSONObject("AccessKey").getString("AccessKeySecret"); | |
Map<String, String> akMap = new HashMap<>(); | |
akMap.put("AccessKeyId", AccessKeyId); | |
akMap.put("AccessKeySecret", AccessKeySecret); | |
return akMap; | |
} | |
public static void CreateLoginProfile(IAcsClient client, String userName, String password) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
CommonResponse response; | |
//DeleteAccessKey | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("CreateLoginProfile"); | |
request.putQueryParameter("UserName", userName); | |
request.putQueryParameter("Password", password); | |
request.putQueryParameter("PasswordResetRequired", "true"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][CreateLoginProfile]:" + response.getData()); | |
} | |
public static void DeleteUser(IAcsClient client, String userName, String userAccessKeyId, boolean deleteUser) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
CommonResponse response; | |
//DeleteAccessKey | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("DeleteAccessKey"); | |
request.putQueryParameter("UserAccessKeyId", userAccessKeyId); | |
request.putQueryParameter("UserName", userName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][DeleteAccessKey]:" + response.getData()); | |
if (deleteUser) { | |
//DetachPolicyFromUser | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("DetachPolicyFromUser"); | |
request.putQueryParameter("PolicyType", "System"); | |
request.putQueryParameter("PolicyName", "AdministratorAccess"); | |
request.putQueryParameter("UserName", userName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][DetachPolicyFromUser]:" + response.getData()); | |
//DeleteUser | |
request.setSysDomain("ram.aliyuncs.com"); | |
request.setSysVersion("2015-05-01"); | |
request.setSysAction("DeleteUser"); | |
request.putQueryParameter("UserName", userName); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
response = client.getCommonResponse(request); | |
loggerInfo("[ram.aliyuncs.com][DeleteUser]:" + response.getData()); | |
} | |
} | |
public static String CreateResourceAccount(IAcsClient client, String displayName, String parentFolderId) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("CreateResourceAccount"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
request.putQueryParameter("DisplayName", displayName); | |
request.putQueryParameter("ParentFolderId", parentFolderId); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][CreateResourceAccount]:" + result); | |
return result; | |
} | |
/** | |
* 升级成云账号,会发送邮件,需要在邮件中"立即确认" | |
* | |
* @param accountId | |
* @param email | |
* @throws Exception | |
*/ | |
public static String PromoteResourceAccount(IAcsClient client, String accountId, String email) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("PromoteResourceAccount"); | |
request.putQueryParameter("AccountId", accountId); | |
request.putQueryParameter("Email", email); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][PromoteResourceAccount]:" + result); | |
return result; | |
} | |
/** | |
* 把云账号从RD中解绑 | |
* | |
* @param accountId | |
* @throws Exception | |
*/ | |
public static String RemoveCloudAccount(IAcsClient client, String accountId) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("RemoveCloudAccount"); | |
request.putQueryParameter("AccountId", accountId); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][RemoveCloudAccount]:" + result); | |
return result; | |
} | |
/** | |
* 开通RD | |
* | |
* @throws Exception | |
*/ | |
public static void initResourceDirectory(IAcsClient client) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("InitResourceDirectory"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
System.out.println(result); | |
} | |
public static String GetResourceDirectory(IAcsClient client) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("GetResourceDirectory"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
try { | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
return result; | |
} catch (ClientException clientException) { | |
if ("ResourceDirectoryNotInUse".equals(clientException.getErrCode())) { | |
return null; | |
} | |
throw clientException; | |
} | |
} | |
public static int ListAccounts(IAcsClient client) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("ListAccounts"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][ListAccounts]:" + result); | |
return JSON.parseObject(result).getInteger("TotalCount"); | |
} | |
public static String GetAccount(IAcsClient client, String accountId) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("GetAccount"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
request.putQueryParameter("AccountId", accountId); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][GetAccount]:" + result); | |
return result; | |
} | |
public static void DestroyResourceDirectory(IAcsClient client) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("DestroyResourceDirectory"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][DestroyResourceDirectory]:" + result); | |
} | |
public static String InviteAccountToResourceDirectory(IAcsClient client, String accountId) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("InviteAccountToResourceDirectory"); | |
request.putQueryParameter("TargetType", "Account"); | |
request.putQueryParameter("TargetEntity", accountId); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][InviteAccountToResourceDirectory]:" + result); | |
return result; | |
} | |
public static String AcceptHandshake(IAcsClient client, String handshakeId) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("resourcemanager.aliyuncs.com"); | |
request.setSysVersion("2020-03-31"); | |
request.setSysAction("AcceptHandshake"); | |
request.putQueryParameter("HandshakeId", handshakeId); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[resourcemanager.aliyuncs.com][AcceptHandshake]:" + result); | |
return result; | |
} | |
public static String GetCallerIdentity(IAcsClient client) throws Exception { | |
CommonRequest request = new CommonRequest(); | |
request.setSysDomain("sts.aliyuncs.com"); | |
request.setSysVersion("2015-04-01"); | |
request.setSysAction("GetCallerIdentity"); | |
request.setSysProtocol(ProtocolType.HTTPS); | |
CommonResponse response = client.getCommonResponse(request); | |
String result = response.getData(); | |
loggerInfo("[sts.aliyuncs.com][GetCallerIdentity]:" + result); | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="zh-CN"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | |
<title>Generator</title> | |
<link href="../../css/bootstrap.min.css" rel="stylesheet"> | |
<script type="text/javascript" src="../../jslib/jquery.min.js"></script> | |
<script type="text/javascript"> | |
let task; | |
$(document).ready(function () { | |
$("#btn_generate").on("click", function () { | |
let accessKeyId = $("input[name='accessKeyId']").val(); | |
let accessKeySecret = $("input[name='accessKeySecret']").val(); | |
let email = $('input[name="email"]').val(); | |
$("#msgBox").show(); | |
$("#msgBox").delay(2000).hide(1000); | |
$.ajax({ | |
url: "../../aliyunTools/createAccount.htm", | |
data: { | |
accessKeyId: accessKeyId, | |
accessKeySecret: accessKeySecret, | |
email: email | |
}, | |
success: function (result) { | |
console.log(result); | |
if (result.success) { | |
task = setInterval(function () { | |
$.ajax({ | |
url: "../../aliyunTools/getProcessById.htm", | |
data: { | |
id: result.data | |
}, | |
success: function (resultInfo) { | |
let log = resultInfo.data; | |
$("#consoleDiv").html(log); | |
if (log.endsWith('__done__')) { | |
clearInterval(task); | |
} | |
} | |
}); | |
}, 1000); | |
} | |
} | |
}); | |
}); | |
}); | |
</script> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>账号生成器</h1> | |
<hr> | |
<h3>旧账号</h3> | |
<br> | |
<div class="form-group"> | |
<label><h4>AccessKeyId</h4></label> | |
<input class="form-control" name="accessKeyId" placeholder="必填"> | |
</div> | |
<div class="form-group"> | |
<label><h4>AccessKeySecret</h4></label> | |
<input class="form-control" name="accessKeySecret" type="password" placeholder="必填"> | |
</div> | |
<br> | |
<h3>新账号</h3> | |
<br> | |
<div class="form-group"> | |
<label><h4>Email</h4></label> | |
<input class="form-control" name="email" placeholder="必填"> | |
</div> | |
<br> | |
<button id="btn_generate" class="btn btn-success"> 生成新账号 </button> | |
<button id="btn_reset" class="btn" type="reset">重置</button> | |
<br> | |
<div id="msgBox" style="display:none" class="alert alert-success" role="alert"> | |
已经提交,请耐心等待! | |
</div> | |
<br> | |
<div id="consoleDiv" style="background-color: black;color: #adb5bd;word-break: break-all;padding: 10px;"> | |
waiting... | |
</div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment