如何在Node.js应用上使用saml2aws类似功能

问题描述

我正在寻找有关如何使用ADFS(用户名和密码)以及MFA身份验证来获取临时访问密钥和秘密密钥以进行进一步操作的方法,以对使用ADFS认证NodeJS服务器我的AWS账户的建议。

作为参考,我正在尝试实现saml2aws在命令行界面上的功能在这里,我想在NodeJS服务器上代替命令行界面。

任何建议将不胜感激。

到目前为止,我已经收到了下面的代码,就像我输入ADFS凭据并提交请求一样,它对我完成了一半工作,然后在我的Microsoft身份验证器应用程序上触发了要批准的通知。但是我的代码不等待验证者的响应。它只是获取网页的正文,在该正文中等待身份验证者批准。我需要某种方式使其等待身份验证器响应,这将在提交ADFS信用后为我提供SAML断言响应。

require("dotenv").config();
const AWS = require("aws-sdk");
const sts = new AWS.STS();
const request = require("request").defaults({ jar: true });
const url = require("url");
const jssoup = require("jssoup").default;
const os = require("os");
const path = require("path");
const fs = require("fs");
const ini = require("ini");

const HOME = os.homedir();
const CONfig_FILE = path.join(HOME,".aws","credentials");

let IDP_URL = process.env.IDP_URL;
let IDP_USER = process.env.IDP_USER;
let IDP_PASS = process.env.IDP_PASS;
let AWS_PROFILE = process.env.AWS_PROFILE;
console.log(IDP_USER);
function base64encode(data) {
  return Buffer.from(data,"utf8").toString("base64");
}

function base64decode(data) {
  return Buffer.from(data,"base64").toString("utf8");
}

function httpGet(url) {
  const options = {
    url,};
  return new Promise((resolve,reject) => {
    request.get(options,(error,response,body) => {
      if (error) {
        reject(error);
      } else {
        resolve({ response,body });
      }
    });
  });
}

function httpPost(url,form) {
  const options = {
    url,form,followAllRedirects: true,reject) => {
    request.post(options,body });
      }
    });
  });
}

function getLoginData(body) {
  const soup = new jssoup(body);
  const forms = soup.findAll("form");
  const form = forms.find((form) => form.attrs.id === "loginForm");

  if (!form) {
    throw new Error("LOGIN_FORM_NOT_FOUND");
  }

  const action = url.resolve(IDP_URL,form.attrs.action);
  const inputs = {};

  for (const input of form.findAll("input")) {
    const name = input.attrs.name || "";
    const value = input.attrs.value || "";
    const namelc = name.toLowerCase();

    if (namelc.includes("user")) {
      inputs[name] = IDP_USER;
    } else if (namelc.includes("email")) {
      inputs[name] = IDP_USER;
    } else if (namelc.includes("pass")) {
      inputs[name] = IDP_PASS;
    } else {
      inputs[name] = value;
    }
  }

  return { action,inputs };
}

function getSAMLAssertion(body) {
  const soup = new jssoup(body);
  const inputs = soup.findAll("input");
  const saml = inputs.find((input) => input.attrs.name === "SAMLResponse");

  if (!saml) {
    throw new Error("SAML_ASSERTION_NOT_FOUND");
  }

  return base64decode(saml.attrs.value);
}

function getSAMLRoles(saml) {
  const soup = new jssoup(saml);
  const roles = soup
    .findAll("AttributeValue")
    .filter((value) => {
      return (
        value.parent &&
        value.parent.name === "Attribute" &&
        value.parent.attrs &&
        value.parent.attrs.Name ===
          "https://aws.amazon.com/SAML/Attributes/Role"
      );
    })
    .map((value) => {
      const [provider,role] = (value.text || "").split(",");
      return { provider,role };
    });

  if (!roles[0]) {
    throw new Error("SAML_ROLE_NOT_FOUND");
  }

  return roles;
}

async function getSTSToken(provider,role,assertion) {
  const params = {
    DurationSeconds: 3600,PrincipalArn: provider,RoleArn: role,SAMLAssertion: base64encode(assertion),reject) => {
    sts.assumeRoleWithSAML(params,data) => {
      if (error) {
        reject(error);
      } else {
        resolve(data);
      }
    });
  });
}

function saveSTSToken(filename,profile,sts) {
  const readFile = () => {
    try {
      return ini.decode(fs.readFileSync(filename,"utf-8"));
    } catch (e) {
      return {};
    }
  };

  const writeFile = (config) => {
    fs.writeFileSync(filename,ini.encode(config,{ whitespace: true }));
  };

  const config = readFile();
  const section = config[profile] || {};
  const credentials = sts.Credentials || {};

  section.aws_access_key_id = credentials.AccessKeyId;
  section.aws_secret_access_key = credentials.SecretAccessKey;
  section.aws_session_token = credentials.SessionToken;

  config[profile] = section;
  writeFile(config);
}

function checkUsage() {
  if (!IDP_URL) {
    throw new Error("IDP_URL not set!");
  }
  if (!IDP_USER) {
    throw new Error("IDP_USER not set!");
  }
  if (!IDP_PASS) {
    throw new Error("IDP_PASS not set!");
  }
  if (!AWS_PROFILE) {
    throw new Error("AWS_PROFILE not set!");
  }
}

(async function main() {
  try {
    console.log(`aws-saml-session started.`);
    checkUsage();

    console.log(`Logging into SAML provider...`);
    const resp1 = await httpGet(IDP_URL);
    const data = getLoginData(resp1.body);
    // This is the place its not waiting and getting me body of the page 
    //where it needs to wait and get me SAML response
    ```const resp2 = await httpPost(data.action,data.inputs);
    const saml = getSAMLAssertion(resp2.body);```

    const roles = getSAMLRoles(saml);

    const { provider,role } = roles[0];

    console.log(`Assuming role: ${role}...`);
    const sts = await getSTSToken(provider,saml);

    console.log(`Saving credentials: ${AWS_PROFILE}...`);
    saveSTSToken(CONfig_FILE,AWS_PROFILE,sts);

    console.log("Done.");
  } catch (e) {
    console.log("ERROR:",e.message);
  }
})();

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...