{"action":"created","comment":{"url":"https://api.github.com/repos/Clever/saml2/pulls/comments/30363618","id":30363618,"diff_hunk":"@@ -1,102 +1,262 @@\n-# SAML2 Library\n+# SAML2-js\n \n-## Description\n+[![Build Status](https://ci.ops.clever.com/api/badge/github.com/Clever/saml2/status.svg?branch=master)](https://ci.ops.clever.com/github.com/Clever/saml2)\n \n-Takes care of the complexities of the SAML protocol and provides an easy interface for using it. Specifically, creating metadata.xml files, creating `AuthnRequest`s and parsing and validating `AuthnResponse`s.\n-\n-This is exposed as both a series of functions that implement each step of the SAML protocol, and an Express middleware that creates the necessary endpoints for the metadata, the login and the assertion.\n+`saml2-js` is a module that abstracts away the complexities of the SAML protocol and provides an easy interface for using it in node.\n \n ## Installation\n \n ```bash\n-  npm install saml2-js\n+  npm install saml2-js --save\n ```\n \n-## Expected Usage\n+## Usage\n \n Include the SAML library.\n \n-```coffee\n-  saml_lib = require('saml')\n+```javascript\n+  var saml2 = require('saml2-js');\n ```\n \n-To use the saml library, we think in terms of service providers (e.g. Clever) and identity providers (e.g. partners that use ADFS).\n+## Documentation\n \n-```coffee\n-  sp = saml_lib.service_provider\n-    private_key : 'saml.pem'\n-    certificate : 'saml.crt'\n+This library exports two constructors.\n \n-  idp = saml_lib.identity_provider\n-    sso_login_url : 'https://www.example.com/login'\n-    sso_logout_url : 'https://www.example.com/logout'\n-    certificate : 'adfs.crt'\n+- [`ServiceProvider`](#ServiceProvider) - Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow.\n+- [`IdentityProvider`](#IdentityProvider) - Represents an online service that authenticates users in the SAML flow.\n \n-```\n+<a name=\"ServiceProvider\" />\n+### ServiceProvider(options)\n+Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow.\n+\n+#### Options\n+- `entity_id` - **Required** - Unique identifier for the service provider, often the url of the metadata file.\n+- `private_key` - **Required** - Private key (PEM format string) for the service provider.\n+- `certificate` - **Required** - Certificate (PEM format string) for the service provider.\n+- `assert_endpoint` - **Required** - URL of service provider assert endpoint.\n+- `force_authn` - Boolean that allows forcing re-authentication of users even if the user has a SSO session with the IdP.  This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis.\n+- `auth_context` - Specifies `AuthnContextClassRef`.  This can also be configured per-method basis.\n+- `nameid_format` - Format for Name ID.  This can also be configured on a per-method basis.\n+- `sign_get_request` -  Boolean, if true signs the request.  This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis.\n+- `allow_unencrypted_assertion` -  Boolean, when set to true allows unencrypted assertions.  This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis.\n \n-Upon creating at least one service provider and one identity provider, you can then create SAML requests between them.\n+#### Returns the following functions\n+- [`create_login_request_url`](#create_login_request_url) - Get a URL to initiate a login.\n+- [`redirect_assert`](#redirect_assert) - Gets a user object if the login attempt is valid, inflates the response before parsing it.\n+- [`post_assert`](#post_assert) - Gets a user object if the login attempt is valid.\n+- [`create_logout_request_url`](#create_logout_request_url)- Creates a request URL to log out the user.\n+- [`create_logout_response_url`](#create_logout_response_url) - Creates a URL to confirm a successful logout.\n+- [`create_metadata`](#create_metadata) - Returns the XML metadata used during the initial SAML configuration.\n \n-```coffee\n-  # -- REQUIRED --\n-  # Returns a redirect URL, at which a user can login\n-  sp.create_login_url(idp, cb)\n+#### Example\n+```javascript\n \n-  # Returns user object, if the login attempt was valid.\n-  sp.assert(idp, request_body, cb)\n+  // Initialize options object\n+  var sp_options = {\n+    entity_id: \"https://sp.example.com/metadata.xml\",\n+    private_key: fs.readFileSync(\"key-file.pem\").toString(),\n+    certificate: fs.readFileSync(\"cert-file.crt\").toString(),\n+    assert_endpoint: \"https://sp.example.com/assert\",\n+    force_authn: true,\n+    auth_context: { comparison: \"exact\", class_refs: [\"urn:oasis:names:tc:SAML:1.0:am:password\"] },\n+    nameid_format: \"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\",\n+    sign_get_request: false,\n+    allow_unencrypted_assertion: true\n+  }\n \n-  # -- OPTIONAL --\n-  # Returns a redirect URL, at which a user is logged out.\n-  sp.create_logout_url(idp, cb)\n+  // Call service provider constructor with options\n+  var sp = saml2.ServiceProvider(sp_options);\n+\n+  // Example use of service provider.\n+  // Call metadata to get XML metatadata used in configuration.\n+  var metadata = sp.create_metadata();\n \n-  # Returns XML containing service-provider parameters.\n-  # For use during initial SAML configuration\n-  sp.create_metadata(idp, cb)\n ```\n \n-## Helper Methods\n+#### Service provider function definitions\n \n-We will break each of the `service_provider` methods into minimal, testable methods.\n+<a name=\"create_login_request_url\" />\n+##### create_login_request_url(IdP, options, cb)\n+Get a URL to initiate a login.\n \n-```coffee\n-  ... TODO ...\n-  parse_xml\n-  parse_assert\n-  createAuthRequest\n-```\n+Takes the following arguments:\n+- `IdP` - [IdP](#IdentityProvider)\n+- `options`\n+  - `relay_state` - SAML relay state.\n+  - `auth_context` - Specifies `AuthnContextClassRef`.  This can also be configured on the [SP](#ServiceProvider).\n+  - `nameid_format` - Format for Name ID.  This can also be configured on a per-method basis.","path":"README.md","position":null,"original_position":127,"commit_id":"05c3010999ef6533b5c74f8443482d249be46852","original_commit_id":"764fd970f3c1eb9bfdd57ccd10eb0557edfb607c","user":{"login":"ipam73","id":4316215,"avatar_url":"https://avatars.githubusercontent.com/u/4316215?v=3","gravatar_id":"","url":"https://api.github.com/users/ipam73","html_url":"https://github.com/ipam73","followers_url":"https://api.github.com/users/ipam73/followers","following_url":"https://api.github.com/users/ipam73/following{/other_user}","gists_url":"https://api.github.com/users/ipam73/gists{/gist_id}","starred_url":"https://api.github.com/users/ipam73/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ipam73/subscriptions","organizations_url":"https://api.github.com/users/ipam73/orgs","repos_url":"https://api.github.com/users/ipam73/repos","events_url":"https://api.github.com/users/ipam73/events{/privacy}","received_events_url":"https://api.github.com/users/ipam73/received_events","type":"User","site_admin":false},"body":"Good catch.\r\n05c3010999ef6533b5c74f8443482d249be46852","created_at":"2015-05-14T21:12:59Z","updated_at":"2015-05-14T21:12:59Z","html_url":"https://github.com/Clever/saml2/pull/32#discussion_r30363618","pull_request_url":"https://api.github.com/repos/Clever/saml2/pulls/32","_links":{"self":{"href":"https://api.github.com/repos/Clever/saml2/pulls/comments/30363618"},"html":{"href":"https://github.com/Clever/saml2/pull/32#discussion_r30363618"},"pull_request":{"href":"https://api.github.com/repos/Clever/saml2/pulls/32"}}},"pull_request":{"url":"https://api.github.com/repos/Clever/saml2/pulls/32","id":34396929,"html_url":"https://github.com/Clever/saml2/pull/32","diff_url":"https://github.com/Clever/saml2/pull/32.diff","patch_url":"https://github.com/Clever/saml2/pull/32.patch","issue_url":"https://api.github.com/repos/Clever/saml2/issues/32","number":32,"state":"open","locked":false,"title":"modify saml interface","user":{"login":"ipam73","id":4316215,"avatar_url":"https://avatars.githubusercontent.com/u/4316215?v=3","gravatar_id":"","url":"https://api.github.com/users/ipam73","html_url":"https://github.com/ipam73","followers_url":"https://api.github.com/users/ipam73/followers","following_url":"https://api.github.com/users/ipam73/following{/other_user}","gists_url":"https://api.github.com/users/ipam73/gists{/gist_id}","starred_url":"https://api.github.com/users/ipam73/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ipam73/subscriptions","organizations_url":"https://api.github.com/users/ipam73/orgs","repos_url":"https://api.github.com/users/ipam73/repos","events_url":"https://api.github.com/users/ipam73/events{/privacy}","received_events_url":"https://api.github.com/users/ipam73/received_events","type":"User","site_admin":false},"body":"**Context:**  The SAML library has changed a lot since it's inception. There are now a fair number of unwieldy interfaces and undocumented flags. We should do a major version bump - unifying the interface, and we should update the documentation to be correct.\r\n\r\n**Changes:**  Interface only changes.  Exported library functions to take in additional options.\r\n\r\n**Testing:**  Updated unit tests, added new unit tests for untested functions.\r\n\r\n**Task:** https://clever.atlassian.net/browse/OAUTH-242\r\n\r\n**Documentation:** WIP\r\n\r\n**Open questions:**\r\n- Did not add testing to test each exported method in regards to number of options passed\r\n- Should options be truly optional and defaulted to {} if not passed?\r\n\r\n","created_at":"2015-04-29T19:25:00Z","updated_at":"2015-05-14T21:12:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e1f8bf4159b08662d7b1fecaa3cdb5cad0875a4d","assignee":{"login":"jefff","id":124665,"avatar_url":"https://avatars.githubusercontent.com/u/124665?v=3","gravatar_id":"","url":"https://api.github.com/users/jefff","html_url":"https://github.com/jefff","followers_url":"https://api.github.com/users/jefff/followers","following_url":"https://api.github.com/users/jefff/following{/other_user}","gists_url":"https://api.github.com/users/jefff/gists{/gist_id}","starred_url":"https://api.github.com/users/jefff/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jefff/subscriptions","organizations_url":"https://api.github.com/users/jefff/orgs","repos_url":"https://api.github.com/users/jefff/repos","events_url":"https://api.github.com/users/jefff/events{/privacy}","received_events_url":"https://api.github.com/users/jefff/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/Clever/saml2/pulls/32/commits","review_comments_url":"https://api.github.com/repos/Clever/saml2/pulls/32/comments","review_comment_url":"https://api.github.com/repos/Clever/saml2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Clever/saml2/issues/32/comments","statuses_url":"https://api.github.com/repos/Clever/saml2/statuses/05c3010999ef6533b5c74f8443482d249be46852","head":{"label":"Clever:OAUTH-242-saml-polish","ref":"OAUTH-242-saml-polish","sha":"05c3010999ef6533b5c74f8443482d249be46852","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":17650054,"name":"saml2","full_name":"Clever/saml2","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/saml2","description":"SAML 2.0 node helpers","fork":false,"url":"https://api.github.com/repos/Clever/saml2","forks_url":"https://api.github.com/repos/Clever/saml2/forks","keys_url":"https://api.github.com/repos/Clever/saml2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/saml2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/saml2/teams","hooks_url":"https://api.github.com/repos/Clever/saml2/hooks","issue_events_url":"https://api.github.com/repos/Clever/saml2/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/saml2/events","assignees_url":"https://api.github.com/repos/Clever/saml2/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/saml2/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/saml2/tags","blobs_url":"https://api.github.com/repos/Clever/saml2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/saml2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/saml2/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/saml2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/saml2/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/saml2/languages","stargazers_url":"https://api.github.com/repos/Clever/saml2/stargazers","contributors_url":"https://api.github.com/repos/Clever/saml2/contributors","subscribers_url":"https://api.github.com/repos/Clever/saml2/subscribers","subscription_url":"https://api.github.com/repos/Clever/saml2/subscription","commits_url":"https://api.github.com/repos/Clever/saml2/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/saml2/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/saml2/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/saml2/issues/comments{/number}","contents_url":"https://api.github.com/repos/Clever/saml2/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/saml2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/saml2/merges","archive_url":"https://api.github.com/repos/Clever/saml2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/saml2/downloads","issues_url":"https://api.github.com/repos/Clever/saml2/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/saml2/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/saml2/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/saml2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/saml2/labels{/name}","releases_url":"https://api.github.com/repos/Clever/saml2/releases{/id}","created_at":"2014-03-12T00:23:44Z","updated_at":"2015-05-08T06:54:44Z","pushed_at":"2015-05-14T21:12:29Z","git_url":"git://github.com/Clever/saml2.git","ssh_url":"git@github.com:Clever/saml2.git","clone_url":"https://github.com/Clever/saml2.git","svn_url":"https://github.com/Clever/saml2","homepage":null,"size":1122,"stargazers_count":7,"watchers_count":7,"language":"CoffeeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":7,"forks":4,"open_issues":7,"watchers":7,"default_branch":"master"}},"base":{"label":"Clever:master","ref":"master","sha":"099ce07a6351ef3d3206431fc5e60089fc51a2b0","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":17650054,"name":"saml2","full_name":"Clever/saml2","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/saml2","description":"SAML 2.0 node helpers","fork":false,"url":"https://api.github.com/repos/Clever/saml2","forks_url":"https://api.github.com/repos/Clever/saml2/forks","keys_url":"https://api.github.com/repos/Clever/saml2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/saml2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/saml2/teams","hooks_url":"https://api.github.com/repos/Clever/saml2/hooks","issue_events_url":"https://api.github.com/repos/Clever/saml2/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/saml2/events","assignees_url":"https://api.github.com/repos/Clever/saml2/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/saml2/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/saml2/tags","blobs_url":"https://api.github.com/repos/Clever/saml2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/saml2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/saml2/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/saml2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/saml2/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/saml2/languages","stargazers_url":"https://api.github.com/repos/Clever/saml2/stargazers","contributors_url":"https://api.github.com/repos/Clever/saml2/contributors","subscribers_url":"https://api.github.com/repos/Clever/saml2/subscribers","subscription_url":"https://api.github.com/repos/Clever/saml2/subscription","commits_url":"https://api.github.com/repos/Clever/saml2/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/saml2/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/saml2/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/saml2/issues/comments{/number}","contents_url":"https://api.github.com/repos/Clever/saml2/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/saml2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/saml2/merges","archive_url":"https://api.github.com/repos/Clever/saml2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/saml2/downloads","issues_url":"https://api.github.com/repos/Clever/saml2/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/saml2/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/saml2/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/saml2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/saml2/labels{/name}","releases_url":"https://api.github.com/repos/Clever/saml2/releases{/id}","created_at":"2014-03-12T00:23:44Z","updated_at":"2015-05-08T06:54:44Z","pushed_at":"2015-05-14T21:12:29Z","git_url":"git://github.com/Clever/saml2.git","ssh_url":"git@github.com:Clever/saml2.git","clone_url":"https://github.com/Clever/saml2.git","svn_url":"https://github.com/Clever/saml2","homepage":null,"size":1122,"stargazers_count":7,"watchers_count":7,"language":"CoffeeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"open_issues_count":7,"forks":4,"open_issues":7,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Clever/saml2/pulls/32"},"html":{"href":"https://github.com/Clever/saml2/pull/32"},"issue":{"href":"https://api.github.com/repos/Clever/saml2/issues/32"},"comments":{"href":"https://api.github.com/repos/Clever/saml2/issues/32/comments"},"review_comments":{"href":"https://api.github.com/repos/Clever/saml2/pulls/32/comments"},"review_comment":{"href":"https://api.github.com/repos/Clever/saml2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Clever/saml2/pulls/32/commits"},"statuses":{"href":"https://api.github.com/repos/Clever/saml2/statuses/05c3010999ef6533b5c74f8443482d249be46852"}}}}