Giter Club home page Giter Club logo

node-samlp's Issues

Need option for keyEncryptionAlgorighm

When calling the auth method, I need to be able to set the keyEncryptionAlgorighm option that gets passed to the saml20.js create method to use a different encryption key. In the meantime I have to fork the project just to add this option. If that could be added it would be greatly appreciated. Thanks guys!

How do I use this?

From the README:

The idea is that you will use another mechanism to validate the user first.

Can you explain the basic workflow flow to include authentication (validate the user)?

I see if req.user is null, then the middleware simply returns a 401. Am I expected to catch this 401, display a login screen or otherwise authenticate the user, then redirect back to the sampl handler with SAMLRequest in the URL again?

Sorry for not getting it...

and Thanks!

SAML assertion signing using HSM

Describe the problem you'd like to have solved

I would like to have my private key stored in my key signing server or HSM. Using an HSM server would provide greater security for the private keys.

Describe the ideal solution

The unsigned XML document should be passed to the HSM server and a signature returned to be embedded in the XML document. The private keys should never leave the HSM.

Alternatives and current work-arounds

No good workarounds are currently available.

Additional context

I have a PR ready for both node-saml and node-samlp, creating this issue just to follow protocol. The solution includes a simple upgrade to allow asynchronous XML signing using a custom function provided by the host application. Unit tests have been created and are passing. The necessary PR's have already been made to xml-crypto version 1.5.3.

I can create the PR once the dependency for node-saml PR is merged

ReDOS (NSP 532)

Hi, we currently make use of your package, and I noticed an open NSP issue regarding moment in the lower package (node-saml) that is still using an unpatched version of moment.

I was wondering if you would be able to update the dependency once your other package (saml) has been patched.

related ticket: auth0/node-saml#38

getAttributeType() of saml20 could be made more specific for number data type

Currently getAttributeType() of saml20.js is sending out all number type as double; can this be modified to send "integer" type too?

Something like,

function getAttributeType(value){
  switch(typeof value) {
    case "string":
      return 'xs:string';
    case "boolean":
      return 'xs:boolean';
    case "number":
      if(value === parseInt(value, 10))
        return 'xs:integer';
      else
        return 'xs:double';
    default:
      return 'xs:anyType';
  }
}

Cannot sign the assertion

According to SAML spec, the SAML response should always be signed and the SAML assertion can optionally be signed. samlp.auth currently only allows for the response to be signed, and it defaults to not signing it.

Desired behavior

The response should always be signed, and there should be an option added signAssertion to sign the assertion as well.

samlp.auth({
    ...,
    signAssertion: true,
});

The above code should result in a SAML response with both a signed response and a signed assertion. The signResponse option should default to true and signAssertion should default to false.

Error when RelayState not provided

If you do not provide a RelayState querystring parameter, the following error is thrown:

     TypeError: Cannot read property 'RelayState' of undefined
      at C:\gh\node-samlp\lib\samlp.js:208:80
      at C:\gh\node-samlp\lib\samlp.js:100:5
      at Object.exports.create (C:\gh\node-samlp\node_modules\saml\lib\saml20.js:138:14)
      at getSamlResponse (C:\gh\node-samlp\lib\samlp.js:44:10)
      at execute (C:\gh\node-samlp\lib\samlp.js:200:5)
      at C:\gh\node-samlp\lib\samlp.js:228:9
      at Object.getPostURL (C:\gh\node-samlp\test\fixture\server.js:48:5)
      at C:\gh\node-samlp\lib\samlp.js:224:15
      at C:\gh\node-samlp\lib\samlp.js:26:7
      at InflateRaw.onEnd (zlib.js:166:5)
      at InflateRaw.EventEmitter.emit (events.js:117:20)
      at _stream_readable.js:920:16
      at process._tickCallback (node.js:415:13)

RelayState is optional in the SAML protocol, so this situation should not throw an error.

401 improvement

Describe the problem you'd like to have solved

I'd like to improve the integration of this library when it comes to 401 responses.

Describe the ideal solution

The README clearly states that The idea is that you will use another mechanism to validate the user first.

However, I think that return res.send(401); should be updated to actually call a default function. Then when configuring this library via auth, you can pass in a function to override the default handling.

This is line with how the library works when it comes to customising handling.

Alternatives and current work-arounds

The current work around is to have some extra middleware that runs before this one to validate the user first. However, I feel that looses a bunch of context when working with auth, and I feel that solution is more inline with how other parts of auth work.

Additional context

I'd be happy to provide a PR if this is something you're interested in.

[Suggestion] - Extract some logic to other node modules

Hey auth0 team,

While working on some SAML implementation with a given Service Provider (in my case AWS), I faced the issue of creating a metadata.xml file and SAML responses. Found a lot of resources on the internet (getting me to some of your tutorials ๐Ÿ˜„) and the logic I needed was part of this project.

While node-samlp is SAML Protocol middleware to create SAMLP identity providers for node.js., I'd like to know what you think about extracting some files to their own node-modules, also used by this project.
Thus, it would be allow more use-cases, not restricting to a middleware-use.

For instance, a node-saml20-generator could be created with all the logic to handle SAML metadata generation, SAML responses, SAML assertion validation (which already exists with the saml20 package).

Creating a metadata.xml file is easy with some tweaks, so are the SAML responses in fact with the options provided, so adding some options to make it more flexible could be really nice!

What do you think about it?

Keep going ๐Ÿ‘

Update xml-crypto to 0.8.1

In our project we are not allowed to have binaries (such as *.exe and etc) in node_modules because of some security restrictions.
Unfortunately, it turned out that one of the dependencies of the samlp contains several binary files...

https://github.com/yaronn/xml-crypto/tree/master/test/validators/XmlCryptoUtilities/XmlCryptoUtilities/bin/Debug

Just recently, they released an update (0.8.1) in which those files were finally .npmignored.

Would you mind to bump xml-crypto dependency, republish samlp npm package and save the world? ๐Ÿ˜ƒ

User claims like email, surname and givenname are not optional

PassportProfileMapper User claims like email, surname and givenname are mandatory now. Could these made as optional? There could be some SP to which one might wish to not send these claims.

Modifying as given below works for me,

lib/claims/PassportProfileMapper.js:42

claims[fm.email]      = this._pu.emails && this._pu.emails[0] && this._pu.emails[0].value;
claims[fm.name]       = this._pu.displayName;
claims[fm.givenname]  = this._pu.name && this._pu.name.givenName;
claims[fm.surname]    = this._pu.name && this._pu.name.familyName;

Dynamically Set Audience

Is it possible to dynamically set the audience option after the request is received? Here is my use case:
I'm building an SSO solution between two systems. Both systems are multi-tenants and users need to be able to SSO into their respective tenant account. For example, users in System X: Tenant 1 should log into System Y: Tenant 1; System X: Tenant 2 logs into System Y: Tenant 2.

SSO is initiated from System X and I'm able to perform the validation in the getPostURL step. I'm also able to determine the appropriate audience URL during this step which is the same as userData.ssoURL in the callback. Is it possible to set the audience value at this point? When I hardcode the audience URL it works so this is just the last step for me to get this fully functional. Thanks

exports.saml = samlp.auth({ audience: 'https://....', issuer: 'the-issuer', cert: fs.readFileSync('...'), key: fs.readFileSync(...'), getPostURL: async function (audience, wreply, req, callback) { const userData = await validateUser(req) req.user = { emails: [{ value: userData.emails }], displayName: userData.id, id: userData.id, name: { givenName: userData.name, familyName: userData.name } } return callback(null, userData.ssoURL) } })

Add Organization Details to samlp.metadata

Describe the problem you'd like to have solved

As a Identity Provider I would like to add the details of my Organization to the IDP XML

  • Organization Name
  • Organization Contact Name
  • Organization Support Email
  • Organization Privacy Policy URL

Describe the ideal solution

samlp.metadata should allow to add other metadata to the IDP XML apart from the default ones

  • If it is already existing (which from the code of the module, I couldn't find any solutions) then I am sorry for raising the request and would request to add examples for the same

Invalid Session Participant

The documentation provides us with what a session participant object should look like but does not provide information for when or where to store/create session participants.
This may just be my misunderstanding but could some documentation regarding how and when to create session participants be provided?

How is destination supposed to be set in SP logout request?

I'm making an "out of the blue" logout request using python3-saml and samlp is raising an error at lib/logout.js:180 (line if (!session && !options.destination) { return next(new Error('Invalid Session Participant')); }). The request contains the Destination attribute, and the saml-idp service is setting the session participants, so why am I getting this error? I get that the request is coming out of nowhere (i.e. no session), but I am including the destination. If I change options.destination on line 180 to requestData.destination then it works. Maybe this is horrifying in terms of security, but I want to at least pose the question. How can I ensure the principal is logged out of the IdP, regardless of having a session or not? The error is raised as a 500 via saml-idp, so it's hard to do any reasonable validation.

Dependency querystring is deprecated. URLSearchParams API should be used instead

Description

Dependency querystring is deprecated

Reproduction

While installing the latest version a warning about the querystring dependency being deprecated is displayed:

% npm install samlp
npm WARN deprecated [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.

added 38 packages, and audited 39 packages in 2s

2 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Environment

  • Version of this library used: 7.1.0
  • Version of the platform or framework used, if applicable:
    node -v
    v20.8.1
    npm -v
    10.1.0
    
  • Other relevant versions (language, server software, OS, browser): macOS Sonoma 14.0

Hoe can I specify the NameIDFormat

Please I have not seen where I can specify a different NameIDFormat other than urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress.

I need to use urn:oasis:names:tc:SAML:1.1:nameid-format:phoneNumber

Thanks.

SAML Response without InResponseTo

I configured Auth0 as a Identity Provider and it is generating the samlp:Response XML with this InResponseTo parameter. But this is incompatible with my Service Provider, so I would like to generate the XML without it.

This attribute appears in the root node and in the saml:SubjectConfirmationData node.

How can I do that? Is this library related to the internal Auth0 SAML system?

Ref: #39

Thanks in advance

SP initiated flow

Hello all,
I am new in SAML. So can anyone help me to integrate this.
Case is:

  1. User login in my website (Stored in my DB).
  2. After login they get a link (WRKIT LINK) on the dashboard.
    WRKIT guys provide me SP.xml. I don't want my user to login on another third party site due to security reason.

I am try to work as https://github.com/auth0/node-samlp
but I am confused. From where I should call bellow code and what parms I should pass here.
app.get('/samlp', samlp.auth({
issuer: 'the-issuer',
cert: fs.readFileSync(path.join(__dirname, 'some-cert.pem')),
key: fs.readFileSync(path.join(__dirname, 'some-cert.key')),
getPostURL: function (wtrealm, wreply, req, callback) {
return callback( null, 'http://someurl.com')
}
}));

same as :
app.get('/samlp/FederationMetadata/2007-06/FederationMetadata.xml', samlp.metadata({
issuer: 'the-issuer',
cert: fs.readFileSync(path.join(__dirname, 'some-cert.pem')),
}));

xmldom dependency issue

Hello,
We have an issue trying to deploy our application that uses this library because the xmldom dependency is pointing to another github repository.
Our deployment servers don't have internet access, we use Nexus internally to host any dependencies.
This is the depedency I'm referring to:
"xmldom": "auth0/xmldom#v0.1.19-auth0_1"

Can this be modified to it refers to a specific version in NPM?

SAMLResponse does NOT include `SubjectConfirmation`

We are trying to integrate with Tableau authentication. But when we post back SAMLResponse to tableau url, we got following error message:

ERROR | requestId=[zMwHp2uk9D], url=[/public/sp/SSO], status=[401], cause=[Error validating SAML message; caused by: Assertion invalidated by subject confirmation - can't be confirmed by the bearer method], displayableMessage=[null], exceptionClass=[null]

Looks like it's looking for SubjectConfirmation section, which is described in SAML2.0 wiki: https://en.wikipedia.org/wiki/SAML_2.0

Current backwards compatability checks are preventing dependencies from being updated.

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Please read through the template below and answer all relevant questions. Your additional work here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Description

Provide a clear and concise description of the issue, including what you expected to happen.

There has been a request to update the node-saml dependency to its current version. issue. I has submitted a PR for this, but the CI is failing. See here. The failure is due to another Auth0 dependency, xml-encryption. This dependency uses default argument values, which are not supported until Node 6. The backwards compatibility checks for this repository checks from Node v4.8.5 onward. The backwards compatibility checks for the xml-encryption repository checks from Node 8 onward.

Since this organization own the node-saml, node-samlp and xml-encryption repository and the node-samlp project utilizes both the node-saml and xml-encryption dependency, it would be helpful for them to have the same backwards compatibility standards, so all repositories can utilize the latest version of each dependency.

Reproduction

Detail the steps taken to reproduce this error, what was expected, and whether this issue can be reproduced consistently or if it is intermittent.

Where applicable, please include:

  • Code sample to reproduce the issue
  • Log files (redact/remove sensitive information)
  • Application settings (redact/remove sensitive information)
  • Screenshots
git checkout lukemarkwordtlibertyits:master
nvm use v4.8.5
npm test

CLI Failure

Environment

Please provide the following:

  • Version of this library used:
  • Version of the platform or framework used, if applicable:
  • Other relevant versions (language, server software, OS, browser):
  • Other modules/plugins/libraries that might be involved:
    Node Version 4.8.5

SAML Response not matching "saml-schema-protocol-2.0.xsd" - Assertion rejected

When signing the entire SAML Response, one of the Service Provider has rejected the Assertion stating the incorrect ordering of Signature element and not compliant with "saml-schema-protocol-2.0.xsd".
According to them and xsd, signature should be always after the Issuer element in the SAML Response or Assertion. In samlp's SAML Response, the Signature element is present in the Response just after the Assertion element - sample response for reference.

Refer the example here and here (Check "SAML Response with Signed Message")

Is it possible to achieve the specified ordering? I have checked samlresponse.ejs but it doesnt seem to be enough to get there. Any help here is appreciated..

Request for help

I need to build a SAML IdP on Node.js and I found this library.

Here is the scenario that I am trying to build:

  1. The IdP accepts SAML requests from an SP;
  2. Then redirects the user to our login page (already developed in another project);
  3. After login, the user will be redirected back to the IdP with confirmation of login;
  4. And then the IdP sends a SAML response back to the SP.

My questions are:

  1. Is this scenario well suited for SAML protocol? Or I need to change it?
  2. Is it possible to this with samlp? Especially redirecting to the login project, as this is not documented on README.md.

Thanks for you help!

Uncaught Exception Error in samlp.logout

Description

samlp throws an uncaught exception when we send request logout request without parameter (e.g.http://localhost:9000/logout)
TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received undefined
at validateString (internal/validators.js:120:11)
at Url.parse (url.js:159:3)
at Object.urlParse [as parse] (url.js:154:13)
at Object.module.exports.appendQueryString (D:\Projects\myloft-auth-saml-idp\node_modules\samlp\lib\utils.js:177:22)
at send (D:\Projects\myloft-auth-saml-idp\node_modules\samlp\lib\logout.js:315:33)
at DeflateRaw.cb (D:\Projects\myloft-auth-saml-idp\node_modules\samlp\lib\logout.js:354:5)
at DeflateRaw.zlibBufferOnEnd (zlib.js:151:10)
at DeflateRaw.emit (events.js:326:22)
at DeflateRaw.EventEmitter.emit (domain.js:483:12)
at endReadableNT (_stream_readable.js:1241:12) {
code: 'ERR_INVALID_ARG_TYPE'
}

Environment

Please provide the following:

  • samlp: 6.0.1
  • express: 4.17.1
  • Windows:10

Npm audit advisories found

In version 7.0.1 npm audit reports following:

{
    "githubAdvisoryId": "GHSA-phwq-j96m-2c2q",
    "githubAdvisoryUrl": "https://github.com/advisories/GHSA-phwq-j96m-2c2q",
    "packagesList": [
      "samlp>ejs"
    ]
  },
  {
    "githubAdvisoryId": "GHSA-wc69-rhjr-hc9g",
    "githubAdvisoryUrl": "https://github.com/advisories/GHSA-wc69-rhjr-hc9g",
    "packagesList": [
      "samlp>saml>moment"
    ]
  }

wish: clarify SAML vs SAMLp

It would be helpful if the README clarified the relationship between "SAMLp" and "SAML", as there's not a clear definition of SAMLp found when searched for:

https://www.google.com/search?q=samlp

The clearest definition I find is that that "SAMLp" is short for "SAML protocol", meaning it's essentially the same thing, or clarifies that "SAML" refers to a "Markup Language",while "SAMLp" refers to the protocol for transmiting SAML documents.

saml:LogoutResponse - at a HTTP-POST binding i can't add "ds" prefix to Signature

samlp/signers.js - line 40 (sig.keyInfoProvider) and 46 (sig.computeSignature):

sig.keyInfoProvider = {
getKeyInfo: function () {
return "<X509Data><X509Certificate>" + pem + "</X509Certificate></X509Data>";
}
};

sig.computeSignature(xml, {
location: {
reference: "//*[local-name(.)='Issuer']",
action: 'after'
}
});

Key info must be configured like a return "<X509Data><X509Certificate>" + pem + "</X509Certificate></X509Data>"; or return "<ds:X509Data><ds:X509Certificate>" + pem + "</ds:X509Certificate></ds:X509Data>";

But this is not possible from outside.

And sig.computeSignature method - i can't add property "prefix" (to xml-crypto package) to be added canonical prefixes "ds".

Math.random() is not cryptographically secure

module.exports.generateUniqueID = function() {

This function is used to generate unique UIDs throughout the SAML library. Given that SAML deals with authentication, it seems like poor practice to not generate random UIDs in a cryptographically secure manner.

Reference: https://nodejs.org/api/crypto.html#crypto_crypto_randomint_min_max_callback
Guidance: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba

redirectEndpointPath documentation

I noticed redirectEndpointPath parameter seems to be not mentioned in the documentation (README might be out of date?)

and while this perhaps counts as feature request, I noticed using an absolute url doesn't, as instead of using url.resolve, the Location is built using just string concatenation (resulting in "{the autodetected host}{redirectEndpointPath even if absolute}")

Integrations with another repository

I have already built a Node.js toolkit for SAML protocol few months ago here, it provides both SP and IdP part with document. Let's see whether you guys want a further integration, I am happy to join the development later on.

Errors do not end up in the express middleware chain

Description

Errors that take place in the middleware does not get put into the express middleware chain. Currently the middleware will simply call res.send to send the notice to the end user.

Reproduction

Just example code without req.user property will cause plaintext "Unauthorized" to be sent to the browser.

Environment

  • Version of this library used: 3.4.1

SAML Request ID is not used in AuthnResponse

When sending SAML request to node-samlp IdP, for the first time, ID in the request is properly used in InResponseTo attribute of Response. But for the subsequent requests, this InResponseTo attribute is not taken from the respective requests, instead, the same ID from the first request is sent as InResponseTo for all requests. I could see this issue always.

Parse logout request in index.js

Can you please add this line in index.js so the library exposes parsing log out request
exports.parseLogoutRequest = require('./samlp').parseLogoutRequest;

Can I get an example code

I'm trying to create an IDP and it would really help if there was an example code for using this library. Can anyone help?

SAML XML is always parsed assuming utf-8 encoding

While reading the SAMLRequest the library converts the base64 string to a Buffer, after that it converts whether to a string without considering if the XML defined a different encoding in the prolog:

<?xml version="1.0" encoding="UTF-8" ?> <== usually UTF-8 is used, in some cases it can contain a different encoding. We should read the rest of XML based on that encoding.

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line

I am trying to generate smalp response and this is the error I am getting:

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Sign.sign (crypto.js:331:26)
at RSASHA256.getSignature (/srv/node_modules/xml-crypto/lib/signed-xml.js:126:22)
at SignedXml.createSignature (/srv/node_modules/xml-crypto/lib/signed-xml.js:719:44)
at SignedXml.computeSignature (/srv/node_modules/xml-crypto/lib/signed-xml.js:510:29)
at Object.exports.create (/srv/node_modules/saml/lib/saml20.js:204:9)
at getSamlResponse (/srv/node_modules/samlp/lib/samlp.js:72:10)
at execute (/srv/node_modules/samlp/lib/samlp.js:144:7)
at /srv/node_modules/samlp/lib/samlp.js:182:9
at Object.getPostURL (/srv/lib/src/sso/index.js:43:16)
at /srv/node_modules/samlp/lib/samlp.js:178:12
at Object.module.exports.parseSamlRequest (/srv/node_modules/samlp/lib/utils.js:85:28)
at /srv/node_modules/samlp/lib/samlp.js:163:11
at exports.handleSAMLRequest (/srv/lib/src/sso/index.js:66:37)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at next (/srv/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/srv/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at /srv/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
at next (/srv/node_modules/express/lib/router/index.js:275:10)
at urlencodedParser (/srv/node_modules/body-parser/lib/types/urlencoded.js:82:7)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/srv/node_modules/express/lib/router/index.js:317:13)
at /srv/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
at next (/srv/node_modules/express/lib/router/index.js:275:10)
at rawParser (/srv/node_modules/body-parser/lib/types/raw.js:58:7)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)

Pin to specific `xmldom` commit

Currently node-samlp has the following dependency:

"xmldom": "https://github.com/auth0/xmldom/tarball/master",

It doesn't look good to not pin to a specific commit. Today auth0/xmldom merged a commit and obviously https://github.com/auth0/xmldom/tarball/master points to a new code now without any change in node-samlp version (+ yarn/npm lock files aren't happy either).

"http://office.google.com" post linkin test example

Hi,
I'm using this module, in order to implement Identity Provider, the test example is very good for clarifications, but I still didn't understand what is the "http://office.google.com" used for?
What is the meaning of this address? Should I replace it, and with which link?
if I leave it as is, I got the following message when trying to reach the file in drive: "Unable to resolve the server's DNS address."

Thanks,
Miriam.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.