简体   繁体   中英

azure active directory get access token using SPN with certificate in msal-node js facing error "ERR_OSSL_PEM_NO_START_LINE "

I am trying to get access token from azure using msal node and need to follow service principle with certificate. Currently i am using key-vault url to read certificate. My references doc is https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/samples/msal-node-samples/auth-code-key-vault/index.js

const msal = require('@azure/msal-node');
const { DefaultAzureCredential } = require('@azure/identity');
const { CertificateClient } = require('@azure/keyvault-certificates');
const { SecretClient } = require('@azure/keyvault-secrets');

const getazureToken = async () => {
  const credential = new DefaultAzureCredential();
  const client = new CertificateClient(config.keyVaultUrl, credential);
  const secretClient = new SecretClient(config.keyVaultUrl, credential);
  const certResponse = await client.getCertificate(config.certificateName);
  const thumbprint = certResponse.properties.x509Thumbprint.toString('hex');
  const secretResponse = await secretClient.getSecret(config.certificateName);
  const privateKey = secretResponse.value;
  await msalApp(thumbprint, privateKey);
};

async function msalApp(thumbprint, privateKey) {
  // Before running the sample, you will need to replace the values in the config
  const msalConfig = {
    auth: {
      clientId: config.azureClientId,
      authority: `${config.authorityUri}${config.tenantId}/`,
      clientCertificate: {
        thumbprint,
        privateKey,
      },
    },
    system: {
      loggerOptions: {
        loggerCallback(loglevel, message, containsPii) {
          console.log('loglevel', loglevel, message);
        },
        piiLoggingEnabled: false,
        logLevel: msal.LogLevel.Verbose,
      },
    },
  };

  // Create msal application object
  const cca = new msal.ConfidentialClientApplication(msalConfig);
  const authCodeUrlParameters = {
    scopes: config.scope,
  };

  cca
    .acquireTokenByClientCredential(authCodeUrlParameters)
    .then((response) => {
      console.log('==========> response', response);
    })
    .catch((error) =>
      console.log('error------------->', JSON.stringify(error))
    );
}

error: 在此处输入图片说明

I have .pfx file of certificate too. If it can be helpful.

solutions is you can extract .pem files from .pfx file of certificate using below code

const forge = require('node-forge');
const fs = require('fs');

const convertPfxToPem = async (keyFile, passphrase) => {
  const keyBase64 = keyFile.toString('base64');
  const p12Der = forge.util.decode64(keyBase64);
  const asn = forge.asn1.fromDer(p12Der);
  const p12 = forge.pkcs12.pkcs12FromAsn1(asn, false, passphrase);

  // Retrieve key data
  const keyData = p12
    .getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })
    [forge.pki.oids.pkcs8ShroudedKeyBag].concat(
      p12.getBags({ bagType: forge.pki.oids.keyBag })[forge.pki.oids.keyBag]
    );

  // Convert a Forge private key to an ASN.1 RSAPrivateKey
  const rsaPrivateKey = forge.pki.privateKeyToAsn1(keyData[0].key);

  // Wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
  const privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

  // Convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
  const privateKey = forge.pki.privateKeyInfoToPem(privateKeyInfo);
  fs.writeFileSync('key.pem', privateKey);

  return {
    key: privateKey,
  };
};

now read .pfx file and store key.pem and use it.

 let key = null;
    if (fs.existsSync(path.resolve(__dirname, '../key.pem'))) {
       key = fs.readFileSync(path.resolve(__dirname, '../key.pem'));
    } else {
       const pemResponse = await convertPfxToPem(
       fs.readFileSync(path.resolve(__dirname, '../certificate.pfx')),
       config.passphrase
       );
       key = pemResponse.key;
    }

and getazureToken look like below

const credential = new DefaultAzureCredential();
  const client = new CertificateClient(config.keyVaultUrl, credential);
  const certResponse = await client.getCertificate(config.certificateName);
  const thumbprint = certResponse.properties.x509Thumbprint.toString('hex');
  let key = null;
  if (fs.existsSync(path.resolve(__dirname, '../key.pem'))) {
    key = fs.readFileSync(path.resolve(__dirname, '../key.pem'));
  } else {
    const pemResponse = await convertPfxToPem(
      fs.readFileSync(path.resolve(__dirname, '../certificate.pfx')),
      config.passphrase
    );
    key = pemResponse.key;
  }
  try {
    const tokenResponse = await msalApp(thumbprint, key);
    return tokenResponse;
  } catch (err) {}

This error may occur when certificate we try to upload in pem format is not formatted properly.

Please check your certificates format in Pem.js file. Please confirm if the contents of pem file ie; certificate string and private key string have the following format: This implies surrounding the key with lines, including 5 hyphens before and after BEGIN / END CERTIFICATE and each in a different line. Something like below

-----BEGIN PRIVATE KEY-----\\nLONG_STRING_HERE\\n-----END PRIVATE KEY-----

(Check if any of the characters or hyphens were missed) You can check your certificate here And then try by removing (white spaces)ie; “\\s” after and before BEGIN / END CERTIFICATE and replacing them with new line “\\n” from both certificate regex and private key regex from pem.js file with the help of functions involved already or manually modify accordingly.

Please check https://github.com/auth0/node-jsonwebtoken/issues/642#issuecomment too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM