<commit_before>_             = require 'underscore'
async         = _.extend require('async'), require('async-ext')
crypto        = require 'crypto'
{parseString} = require 'xml2js'
url           = require 'url'
util          = require 'util'
xmlbuilder    = require 'xmlbuilder'
xmlcrypto     = require 'xml-crypto'
xmldom        = require 'xmldom'
xmlenc        = require 'xml-encryption'
zlib          = require 'zlib'

# Creates an AuthnRequest and returns it as a string of xml along with the randomly generated ID for the created
# request.
create_authn_request = (issuer, assert_endpoint, destination) ->
  id = '_' + crypto.randomBytes(21).toString('hex')
  xml = xmlbuilder.create
    AuthnRequest:
      '@xmlns': 'urn:oasis:names:tc:SAML:2.0:protocol'
      '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
      '@Version': '2.0'
      '@ID': id
      '@IssueInstant': (new Date()).toISOString()
      '@Destination': destination
      '@AssertionConsumerServiceURL': assert_endpoint
      '@ProtocolBinding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
      'saml:Issuer': issuer
      NameIDPolicy:
        '@Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'
        '@AllowCreate': 'true'
  .end()
  { id, xml }

# Creates metadata and returns it as a string of xml. The metadata has one POST assertion endpoint.
create_metadata = (issuer, assert_endpoint, signing_certificate, encryption_certificate) ->
  xmlbuilder.create
    'md:EntityDescriptor':
      '@xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata'
      '@xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#'
      '@entityID': issuer
      'md:SPSSODescriptor': [
          '@protocolSupportEnumeration': 'urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol',
          { 'md:KeyDescriptor': certificate_to_keyinfo('signing', signing_certificate) },
          { 'md:KeyDescriptor': certificate_to_keyinfo('encryption', encryption_certificate) },
          'md:AssertionConsumerService':
            '@Binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
            '@Location': assert_endpoint
            '@index': '0'
        ]
  .end()

# Creates a LogoutRequest and returns it as a string of xml.
create_logout_request = (issuer, name_id, session_index) ->
  xmlbuilder.create
    'samlp:LogoutRequest':
      '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol'
      '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
      '@ID': '_' + crypto.randomBytes(21).toString('hex')
      '@Version': '2.0'
      '@IssueInstant': (new Date()).toISOString()
      'saml:Issuer': issuer
      'saml:NameID': name_id
      'samlp:SessionIndex': session_index
  .end()

# Converts a pem certificate to a KeyInfo object for use with XML.
certificate_to_keyinfo = (use, certificate) ->
  cert_data = /-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec certificate
  throw new Error('Invalid Certificate') if cert_data?.length is 0

  {
    '@use': use
    'ds:KeyInfo':
      '@xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#'
      'ds:X509Data':
        'ds:X509Certificate':
          cert_data[1].replace(/[\r\n|\n]/g, '')<commit_msg>Add destination to LogoutRequest as it's required by ADFS.<commit_after>_             = require 'underscore'
async         = _.extend require('async'), require('async-ext')
crypto        = require 'crypto'
{parseString} = require 'xml2js'
url           = require 'url'
util          = require 'util'
xmlbuilder    = require 'xmlbuilder'
xmlcrypto     = require 'xml-crypto'
xmldom        = require 'xmldom'
xmlenc        = require 'xml-encryption'
zlib          = require 'zlib'

# Creates an AuthnRequest and returns it as a string of xml along with the randomly generated ID for the created
# request.
create_authn_request = (issuer, assert_endpoint, destination) ->
  id = '_' + crypto.randomBytes(21).toString('hex')
  xml = xmlbuilder.create
    AuthnRequest:
      '@xmlns': 'urn:oasis:names:tc:SAML:2.0:protocol'
      '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
      '@Version': '2.0'
      '@ID': id
      '@IssueInstant': (new Date()).toISOString()
      '@Destination': destination
      '@AssertionConsumerServiceURL': assert_endpoint
      '@ProtocolBinding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
      'saml:Issuer': issuer
      NameIDPolicy:
        '@Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'
        '@AllowCreate': 'true'
  .end()
  { id, xml }

# Creates metadata and returns it as a string of xml. The metadata has one POST assertion endpoint.
create_metadata = (issuer, assert_endpoint, signing_certificate, encryption_certificate) ->
  xmlbuilder.create
    'md:EntityDescriptor':
      '@xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata'
      '@xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#'
      '@entityID': issuer
      'md:SPSSODescriptor': [
          '@protocolSupportEnumeration': 'urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol',
          { 'md:KeyDescriptor': certificate_to_keyinfo('signing', signing_certificate) },
          { 'md:KeyDescriptor': certificate_to_keyinfo('encryption', encryption_certificate) },
          'md:AssertionConsumerService':
            '@Binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
            '@Location': assert_endpoint
            '@index': '0'
        ]
  .end()

# Creates a LogoutRequest and returns it as a string of xml.
create_logout_request = (issuer, name_id, session_index, destination) ->
  xmlbuilder.create
    'samlp:LogoutRequest':
      '@xmlns:samlp': 'urn:oasis:names:tc:SAML:2.0:protocol'
      '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
      '@ID': '_' + crypto.randomBytes(21).toString('hex')
      '@Version': '2.0'
      '@IssueInstant': (new Date()).toISOString()
      '@Destination': destination
      'saml:Issuer': issuer
      'saml:NameID': name_id
      'samlp:SessionIndex': session_index
  .end()

# Converts a pem certificate to a KeyInfo object for use with XML.
certificate_to_keyinfo = (use, certificate) ->
  cert_data = /-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec certificate
  throw new Error('Invalid Certificate') if cert_data?.length is 0

  {
    '@use': use
    'ds:KeyInfo':
      '@xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#'
      'ds:X509Data':
        'ds:X509Certificate':
          cert_data[1].replace(/[\r\n|\n]/g, '')
{'fraction_non_alphanumeric': 0.15447784319801675, 'fraction_numerical': 0.016114037806011776, 'mean_word_length': 3.4242631939684713, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 52}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7172979', 'n_tokens_mistral': 2213, 'n_tokens_neox': 2182, 'n_words': 431}