@boxyhq/saml-jackson 1.33.0 → 1.33.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/dist/controller/oauth/oidc-client.d.ts +3 -3
  2. package/dist/controller/oauth/oidc-client.js +2 -1
  3. package/dist/controller/oauth/oidc-client.js.map +1 -1
  4. package/dist/controller/oauth/oidc-issuer.d.ts +2 -0
  5. package/dist/controller/oauth/oidc-issuer.js +25 -0
  6. package/dist/controller/oauth/oidc-issuer.js.map +1 -0
  7. package/dist/controller/oauth.js +36 -35
  8. package/dist/controller/oauth.js.map +1 -1
  9. package/dist/controller/sso-handler.js +1 -1
  10. package/dist/controller/sso-handler.js.map +1 -1
  11. package/dist/controller/utils.d.ts +5 -3
  12. package/dist/controller/utils.js +10 -2
  13. package/dist/controller/utils.js.map +1 -1
  14. package/dist/src/controller/admin.d.ts +27 -0
  15. package/dist/src/controller/admin.js +60 -0
  16. package/dist/src/controller/admin.js.map +1 -0
  17. package/dist/src/controller/analytics.d.ts +16 -0
  18. package/dist/src/controller/analytics.js +79 -0
  19. package/dist/src/controller/analytics.js.map +1 -0
  20. package/dist/src/controller/api.d.ts +557 -0
  21. package/dist/src/controller/api.js +806 -0
  22. package/dist/src/controller/api.js.map +1 -0
  23. package/dist/src/controller/connection/oidc.d.ts +7 -0
  24. package/dist/src/controller/connection/oidc.js +181 -0
  25. package/dist/src/controller/connection/oidc.js.map +1 -0
  26. package/dist/src/controller/connection/saml.d.ts +7 -0
  27. package/dist/src/controller/connection/saml.js +250 -0
  28. package/dist/src/controller/connection/saml.js.map +1 -0
  29. package/dist/src/controller/error.d.ts +10 -0
  30. package/dist/src/controller/error.js +13 -0
  31. package/dist/src/controller/error.js.map +1 -0
  32. package/dist/src/controller/health-check.d.ts +11 -0
  33. package/dist/src/controller/health-check.js +51 -0
  34. package/dist/src/controller/health-check.js.map +1 -0
  35. package/dist/src/controller/logout.d.ts +18 -0
  36. package/dist/src/controller/logout.js +132 -0
  37. package/dist/src/controller/logout.js.map +1 -0
  38. package/dist/src/controller/oauth/allowed.d.ts +1 -0
  39. package/dist/src/controller/oauth/allowed.js +30 -0
  40. package/dist/src/controller/oauth/allowed.js.map +1 -0
  41. package/dist/src/controller/oauth/code-verifier.d.ts +1 -0
  42. package/dist/src/controller/oauth/code-verifier.js +8 -0
  43. package/dist/src/controller/oauth/code-verifier.js.map +1 -0
  44. package/dist/src/controller/oauth/oidc-client.d.ts +12 -0
  45. package/dist/src/controller/oauth/oidc-client.js +89 -0
  46. package/dist/src/controller/oauth/oidc-client.js.map +1 -0
  47. package/dist/src/controller/oauth/redirect.d.ts +1 -0
  48. package/dist/src/controller/oauth/redirect.js +13 -0
  49. package/dist/src/controller/oauth/redirect.js.map +1 -0
  50. package/dist/src/controller/oauth.d.ts +142 -0
  51. package/dist/src/controller/oauth.js +1112 -0
  52. package/dist/src/controller/oauth.js.map +1 -0
  53. package/dist/src/controller/oidc-discovery.d.ts +22 -0
  54. package/dist/src/controller/oidc-discovery.js +47 -0
  55. package/dist/src/controller/oidc-discovery.js.map +1 -0
  56. package/dist/src/controller/setup-link.d.ts +307 -0
  57. package/dist/src/controller/setup-link.js +462 -0
  58. package/dist/src/controller/setup-link.js.map +1 -0
  59. package/dist/src/controller/sp-config.d.ts +22 -0
  60. package/dist/src/controller/sp-config.js +89 -0
  61. package/dist/src/controller/sp-config.js.map +1 -0
  62. package/dist/src/controller/sso-handler.d.ts +66 -0
  63. package/dist/src/controller/sso-handler.js +306 -0
  64. package/dist/src/controller/sso-handler.js.map +1 -0
  65. package/dist/src/controller/utils.d.ts +84 -0
  66. package/dist/src/controller/utils.js +328 -0
  67. package/dist/src/controller/utils.js.map +1 -0
  68. package/dist/src/cron/lock.d.ts +18 -0
  69. package/dist/src/cron/lock.js +98 -0
  70. package/dist/src/cron/lock.js.map +1 -0
  71. package/dist/src/db/db.d.ts +5 -0
  72. package/dist/src/db/db.js +178 -0
  73. package/dist/src/db/db.js.map +1 -0
  74. package/dist/src/db/defaultDb.d.ts +2 -0
  75. package/dist/src/db/defaultDb.js +18 -0
  76. package/dist/src/db/defaultDb.js.map +1 -0
  77. package/dist/src/db/dynamoDb.d.ts +19 -0
  78. package/dist/src/db/dynamoDb.js +320 -0
  79. package/dist/src/db/dynamoDb.js.map +1 -0
  80. package/dist/src/db/encrypter.d.ts +3 -0
  81. package/dist/src/db/encrypter.js +22 -0
  82. package/dist/src/db/encrypter.js.map +1 -0
  83. package/dist/src/db/mem.d.ts +23 -0
  84. package/dist/src/db/mem.js +186 -0
  85. package/dist/src/db/mem.js.map +1 -0
  86. package/dist/src/db/mongo.d.ts +22 -0
  87. package/dist/src/db/mongo.js +177 -0
  88. package/dist/src/db/mongo.js.map +1 -0
  89. package/dist/src/db/planetscale/entity/JacksonIndex.d.ts +5 -0
  90. package/dist/src/db/planetscale/entity/JacksonIndex.js +32 -0
  91. package/dist/src/db/planetscale/entity/JacksonIndex.js.map +1 -0
  92. package/dist/src/db/planetscale/entity/JacksonStore.d.ts +9 -0
  93. package/dist/src/db/planetscale/entity/JacksonStore.js +63 -0
  94. package/dist/src/db/planetscale/entity/JacksonStore.js.map +1 -0
  95. package/dist/src/db/planetscale/entity/JacksonTTL.d.ts +4 -0
  96. package/dist/src/db/planetscale/entity/JacksonTTL.js +27 -0
  97. package/dist/src/db/planetscale/entity/JacksonTTL.js.map +1 -0
  98. package/dist/src/db/redis.d.ts +18 -0
  99. package/dist/src/db/redis.js +214 -0
  100. package/dist/src/db/redis.js.map +1 -0
  101. package/dist/src/db/sql/entity/JacksonIndex.d.ts +7 -0
  102. package/dist/src/db/sql/entity/JacksonIndex.js +39 -0
  103. package/dist/src/db/sql/entity/JacksonIndex.js.map +1 -0
  104. package/dist/src/db/sql/entity/JacksonStore.d.ts +9 -0
  105. package/dist/src/db/sql/entity/JacksonStore.js +61 -0
  106. package/dist/src/db/sql/entity/JacksonStore.js.map +1 -0
  107. package/dist/src/db/sql/entity/JacksonTTL.d.ts +4 -0
  108. package/dist/src/db/sql/entity/JacksonTTL.js +27 -0
  109. package/dist/src/db/sql/entity/JacksonTTL.js.map +1 -0
  110. package/dist/src/db/sql/mariadb/entity/JacksonIndex.d.ts +7 -0
  111. package/dist/src/db/sql/mariadb/entity/JacksonIndex.js +39 -0
  112. package/dist/src/db/sql/mariadb/entity/JacksonIndex.js.map +1 -0
  113. package/dist/src/db/sql/mariadb/entity/JacksonStore.d.ts +9 -0
  114. package/dist/src/db/sql/mariadb/entity/JacksonStore.js +63 -0
  115. package/dist/src/db/sql/mariadb/entity/JacksonStore.js.map +1 -0
  116. package/dist/src/db/sql/mariadb/entity/JacksonTTL.d.ts +4 -0
  117. package/dist/src/db/sql/mariadb/entity/JacksonTTL.js +27 -0
  118. package/dist/src/db/sql/mariadb/entity/JacksonTTL.js.map +1 -0
  119. package/dist/src/db/sql/mssql/entity/JacksonIndex.d.ts +7 -0
  120. package/dist/src/db/sql/mssql/entity/JacksonIndex.js +39 -0
  121. package/dist/src/db/sql/mssql/entity/JacksonIndex.js.map +1 -0
  122. package/dist/src/db/sql/mssql/entity/JacksonStore.d.ts +9 -0
  123. package/dist/src/db/sql/mssql/entity/JacksonStore.js +61 -0
  124. package/dist/src/db/sql/mssql/entity/JacksonStore.js.map +1 -0
  125. package/dist/src/db/sql/mssql/entity/JacksonTTL.d.ts +4 -0
  126. package/dist/src/db/sql/mssql/entity/JacksonTTL.js +27 -0
  127. package/dist/src/db/sql/mssql/entity/JacksonTTL.js.map +1 -0
  128. package/dist/src/db/sql/mssql.d.ts +1 -0
  129. package/dist/src/db/sql/mssql.js +44 -0
  130. package/dist/src/db/sql/mssql.js.map +1 -0
  131. package/dist/src/db/sql/sql.d.ts +32 -0
  132. package/dist/src/db/sql/sql.js +318 -0
  133. package/dist/src/db/sql/sql.js.map +1 -0
  134. package/dist/src/db/sql/sqlite/entity/JacksonIndex.d.ts +7 -0
  135. package/dist/src/db/sql/sqlite/entity/JacksonIndex.js +39 -0
  136. package/dist/src/db/sql/sqlite/entity/JacksonIndex.js.map +1 -0
  137. package/dist/src/db/sql/sqlite/entity/JacksonStore.d.ts +9 -0
  138. package/dist/src/db/sql/sqlite/entity/JacksonStore.js +61 -0
  139. package/dist/src/db/sql/sqlite/entity/JacksonStore.js.map +1 -0
  140. package/dist/src/db/sql/sqlite/entity/JacksonTTL.d.ts +4 -0
  141. package/dist/src/db/sql/sqlite/entity/JacksonTTL.js +27 -0
  142. package/dist/src/db/sql/sqlite/entity/JacksonTTL.js.map +1 -0
  143. package/dist/src/db/store.d.ts +5 -0
  144. package/dist/src/db/store.js +65 -0
  145. package/dist/src/db/store.js.map +1 -0
  146. package/dist/src/db/utils.d.ts +16 -0
  147. package/dist/src/db/utils.js +28 -0
  148. package/dist/src/db/utils.js.map +1 -0
  149. package/dist/src/directory-sync/batch-events/queue.d.ts +40 -0
  150. package/dist/src/directory-sync/batch-events/queue.js +225 -0
  151. package/dist/src/directory-sync/batch-events/queue.js.map +1 -0
  152. package/dist/src/directory-sync/index.d.ts +27 -0
  153. package/dist/src/directory-sync/index.js +97 -0
  154. package/dist/src/directory-sync/index.js.map +1 -0
  155. package/dist/src/directory-sync/non-scim/google/api.d.ts +36 -0
  156. package/dist/src/directory-sync/non-scim/google/api.js +143 -0
  157. package/dist/src/directory-sync/non-scim/google/api.js.map +1 -0
  158. package/dist/src/directory-sync/non-scim/google/index.d.ts +12 -0
  159. package/dist/src/directory-sync/non-scim/google/index.js +10 -0
  160. package/dist/src/directory-sync/non-scim/google/index.js.map +1 -0
  161. package/dist/src/directory-sync/non-scim/google/oauth.d.ts +27 -0
  162. package/dist/src/directory-sync/non-scim/google/oauth.js +105 -0
  163. package/dist/src/directory-sync/non-scim/google/oauth.js.map +1 -0
  164. package/dist/src/directory-sync/non-scim/index.d.ts +24 -0
  165. package/dist/src/directory-sync/non-scim/index.js +85 -0
  166. package/dist/src/directory-sync/non-scim/index.js.map +1 -0
  167. package/dist/src/directory-sync/non-scim/syncGroupMembers.d.ts +23 -0
  168. package/dist/src/directory-sync/non-scim/syncGroupMembers.js +105 -0
  169. package/dist/src/directory-sync/non-scim/syncGroupMembers.js.map +1 -0
  170. package/dist/src/directory-sync/non-scim/syncGroups.d.ts +24 -0
  171. package/dist/src/directory-sync/non-scim/syncGroups.js +120 -0
  172. package/dist/src/directory-sync/non-scim/syncGroups.js.map +1 -0
  173. package/dist/src/directory-sync/non-scim/syncUsers.d.ts +24 -0
  174. package/dist/src/directory-sync/non-scim/syncUsers.js +120 -0
  175. package/dist/src/directory-sync/non-scim/syncUsers.js.map +1 -0
  176. package/dist/src/directory-sync/non-scim/utils.d.ts +36 -0
  177. package/dist/src/directory-sync/non-scim/utils.js +109 -0
  178. package/dist/src/directory-sync/non-scim/utils.js.map +1 -0
  179. package/dist/src/directory-sync/request.d.ts +14 -0
  180. package/dist/src/directory-sync/request.js +29 -0
  181. package/dist/src/directory-sync/request.js.map +1 -0
  182. package/dist/src/directory-sync/scim/Base.d.ts +12 -0
  183. package/dist/src/directory-sync/scim/Base.js +23 -0
  184. package/dist/src/directory-sync/scim/Base.js.map +1 -0
  185. package/dist/src/directory-sync/scim/DirectoryConfig.d.ts +343 -0
  186. package/dist/src/directory-sync/scim/DirectoryConfig.js +580 -0
  187. package/dist/src/directory-sync/scim/DirectoryConfig.js.map +1 -0
  188. package/dist/src/directory-sync/scim/DirectoryGroups.d.ts +28 -0
  189. package/dist/src/directory-sync/scim/DirectoryGroups.js +252 -0
  190. package/dist/src/directory-sync/scim/DirectoryGroups.js.map +1 -0
  191. package/dist/src/directory-sync/scim/DirectoryUsers.d.ts +25 -0
  192. package/dist/src/directory-sync/scim/DirectoryUsers.js +193 -0
  193. package/dist/src/directory-sync/scim/DirectoryUsers.js.map +1 -0
  194. package/dist/src/directory-sync/scim/Groups.d.ts +166 -0
  195. package/dist/src/directory-sync/scim/Groups.js +348 -0
  196. package/dist/src/directory-sync/scim/Groups.js.map +1 -0
  197. package/dist/src/directory-sync/scim/Users.d.ts +99 -0
  198. package/dist/src/directory-sync/scim/Users.js +215 -0
  199. package/dist/src/directory-sync/scim/Users.js.map +1 -0
  200. package/dist/src/directory-sync/scim/WebhookEventsLogger.d.ts +101 -0
  201. package/dist/src/directory-sync/scim/WebhookEventsLogger.js +165 -0
  202. package/dist/src/directory-sync/scim/WebhookEventsLogger.js.map +1 -0
  203. package/dist/src/directory-sync/scim/transform.d.ts +6 -0
  204. package/dist/src/directory-sync/scim/transform.js +37 -0
  205. package/dist/src/directory-sync/scim/transform.js.map +1 -0
  206. package/dist/src/directory-sync/scim/utils.d.ts +33 -0
  207. package/dist/src/directory-sync/scim/utils.js +129 -0
  208. package/dist/src/directory-sync/scim/utils.js.map +1 -0
  209. package/dist/src/directory-sync/types.d.ts +195 -0
  210. package/dist/src/directory-sync/types.js +10 -0
  211. package/dist/src/directory-sync/types.js.map +1 -0
  212. package/dist/src/directory-sync/utils.d.ts +19 -0
  213. package/dist/src/directory-sync/utils.js +56 -0
  214. package/dist/src/directory-sync/utils.js.map +1 -0
  215. package/dist/src/ee/branding/index.d.ts +17 -0
  216. package/dist/src/ee/branding/index.js +49 -0
  217. package/dist/src/ee/branding/index.js.map +1 -0
  218. package/dist/src/ee/common/checkLicense.d.ts +3 -0
  219. package/dist/src/ee/common/checkLicense.js +23 -0
  220. package/dist/src/ee/common/checkLicense.js.map +1 -0
  221. package/dist/src/ee/identity-federation/app.d.ts +328 -0
  222. package/dist/src/ee/identity-federation/app.js +532 -0
  223. package/dist/src/ee/identity-federation/app.js.map +1 -0
  224. package/dist/src/ee/identity-federation/idp-login.d.ts +18 -0
  225. package/dist/src/ee/identity-federation/idp-login.js +98 -0
  226. package/dist/src/ee/identity-federation/idp-login.js.map +1 -0
  227. package/dist/src/ee/identity-federation/index.d.ts +15 -0
  228. package/dist/src/ee/identity-federation/index.js +43 -0
  229. package/dist/src/ee/identity-federation/index.js.map +1 -0
  230. package/dist/src/ee/identity-federation/sso.d.ts +24 -0
  231. package/dist/src/ee/identity-federation/sso.js +124 -0
  232. package/dist/src/ee/identity-federation/sso.js.map +1 -0
  233. package/dist/src/ee/identity-federation/types.d.ts +38 -0
  234. package/dist/src/ee/identity-federation/types.js +2 -0
  235. package/dist/src/ee/identity-federation/types.js.map +1 -0
  236. package/dist/src/ee/ory/ory.d.ts +18 -0
  237. package/dist/src/ee/ory/ory.js +195 -0
  238. package/dist/src/ee/ory/ory.js.map +1 -0
  239. package/dist/src/ee/product/index.d.ts +14 -0
  240. package/dist/src/ee/product/index.js +45 -0
  241. package/dist/src/ee/product/index.js.map +1 -0
  242. package/dist/src/event/axios.d.ts +2 -0
  243. package/dist/src/event/axios.js +27 -0
  244. package/dist/src/event/axios.js.map +1 -0
  245. package/dist/src/event/index.d.ts +11 -0
  246. package/dist/src/event/index.js +53 -0
  247. package/dist/src/event/index.js.map +1 -0
  248. package/dist/src/event/types.d.ts +21 -0
  249. package/dist/src/event/types.js +2 -0
  250. package/dist/src/event/types.js.map +1 -0
  251. package/dist/src/event/utils.d.ts +4 -0
  252. package/dist/src/event/utils.js +33 -0
  253. package/dist/src/event/utils.js.map +1 -0
  254. package/dist/src/event/webhook.d.ts +3 -0
  255. package/dist/src/event/webhook.js +34 -0
  256. package/dist/src/event/webhook.js.map +1 -0
  257. package/dist/src/index.d.ts +35 -0
  258. package/dist/src/index.js +161 -0
  259. package/dist/src/index.js.map +1 -0
  260. package/dist/src/loadConnection.d.ts +4 -0
  261. package/dist/src/loadConnection.js +38 -0
  262. package/dist/src/loadConnection.js.map +1 -0
  263. package/dist/src/opentelemetry/metrics.d.ts +14 -0
  264. package/dist/src/opentelemetry/metrics.js +64 -0
  265. package/dist/src/opentelemetry/metrics.js.map +1 -0
  266. package/dist/src/saml/claims.d.ts +12 -0
  267. package/dist/src/saml/claims.js +57 -0
  268. package/dist/src/saml/claims.js.map +1 -0
  269. package/dist/src/saml/lib.d.ts +8 -0
  270. package/dist/src/saml/lib.js +29 -0
  271. package/dist/src/saml/lib.js.map +1 -0
  272. package/dist/src/saml/x509.d.ts +9 -0
  273. package/dist/src/saml/x509.js +93 -0
  274. package/dist/src/saml/x509.js.map +1 -0
  275. package/dist/src/sso-traces/index.d.ts +114 -0
  276. package/dist/src/sso-traces/index.js +229 -0
  277. package/dist/src/sso-traces/index.js.map +1 -0
  278. package/dist/src/sso-traces/types.d.ts +44 -0
  279. package/dist/src/sso-traces/types.js +2 -0
  280. package/dist/src/sso-traces/types.js.map +1 -0
  281. package/dist/src/typings.d.ts +540 -0
  282. package/dist/src/typings.js +5 -0
  283. package/dist/src/typings.js.map +1 -0
  284. package/dist/typeorm.d.ts +3 -0
  285. package/dist/typeorm.js +58 -0
  286. package/dist/typeorm.js.map +1 -0
  287. package/dist/typings.d.ts +1 -1
  288. package/package.json +7 -7
@@ -0,0 +1,1112 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ import crypto from 'crypto';
22
+ import * as jose from 'jose';
23
+ import { promisify } from 'util';
24
+ import { deflateRaw } from 'zlib';
25
+ import saml from '@boxyhq/saml20';
26
+ import { clientIDFederatedPrefix, clientIDOIDCPrefix, relayStatePrefix, IndexNames, OAuthErrorResponse, getErrorMessage, loadJWSPrivateKey, computeKid, isJWSKeyPairLoaded, extractOIDCUserProfile, getScopeValues, getEncodedTenantProduct, isConnectionActive, } from './utils';
27
+ import * as metrics from '../opentelemetry/metrics';
28
+ import { JacksonError } from './error';
29
+ import * as allowed from './oauth/allowed';
30
+ import * as codeVerifier from './oauth/code-verifier';
31
+ import * as redirect from './oauth/redirect';
32
+ import { getDefaultCertificate } from '../saml/x509';
33
+ import { SSOHandler } from './sso-handler';
34
+ import { extractSAMLResponseAttributes } from '../saml/lib';
35
+ import { oidcClientConfig } from './oauth/oidc-client';
36
+ const deflateRawAsync = promisify(deflateRaw);
37
+ export class OAuthController {
38
+ constructor({ connectionStore, sessionStore, codeStore, tokenStore, ssoTraces, opts, idFedApp }) {
39
+ this.connectionStore = connectionStore;
40
+ this.sessionStore = sessionStore;
41
+ this.codeStore = codeStore;
42
+ this.tokenStore = tokenStore;
43
+ this.ssoTraces = ssoTraces;
44
+ this.opts = opts;
45
+ this.idFedApp = idFedApp;
46
+ this.ssoHandler = new SSOHandler({
47
+ connection: connectionStore,
48
+ session: sessionStore,
49
+ opts,
50
+ });
51
+ }
52
+ authorize(body) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ var _a, _b, _c;
55
+ const { tenant, product, access_type, resource, response_type = 'code', client_id, redirect_uri, state, scope, nonce, code_challenge, code_challenge_method = '', idp_hint, forceAuthn = 'false', login_hint } = body, oidcParams = __rest(body, ["tenant", "product", "access_type", "resource", "response_type", "client_id", "redirect_uri", "state", "scope", "nonce", "code_challenge", "code_challenge_method", "idp_hint", "forceAuthn", "login_hint"]) // Rest of the params will be assumed as OIDC params and will be forwarded to the IdP
56
+ ;
57
+ let requestedTenant;
58
+ let requestedProduct;
59
+ let requestedScopes;
60
+ let requestedOIDCFlow;
61
+ let isOIDCFederated;
62
+ let connection;
63
+ let fedApp;
64
+ try {
65
+ requestedTenant = tenant;
66
+ requestedProduct = product;
67
+ metrics.increment('oauthAuthorize');
68
+ if (!redirect_uri) {
69
+ throw new JacksonError('Please specify a redirect URL.', 400);
70
+ }
71
+ requestedScopes = getScopeValues(scope);
72
+ requestedOIDCFlow = requestedScopes.includes('openid');
73
+ if (tenant && product) {
74
+ const response = yield this.ssoHandler.resolveConnection({
75
+ tenant,
76
+ product,
77
+ idp_hint,
78
+ authFlow: 'oauth',
79
+ originalParams: Object.assign({}, body),
80
+ });
81
+ if ('redirectUrl' in response) {
82
+ return {
83
+ redirect_url: response.redirectUrl,
84
+ };
85
+ }
86
+ if ('connection' in response) {
87
+ connection = response.connection;
88
+ }
89
+ }
90
+ else if (client_id && client_id !== '' && client_id !== 'undefined' && client_id !== 'null') {
91
+ // if tenant and product are encoded in the client_id then we parse it and check for the relevant connection(s)
92
+ let sp = getEncodedTenantProduct(client_id);
93
+ if (!sp && access_type) {
94
+ sp = getEncodedTenantProduct(access_type);
95
+ }
96
+ if (!sp && resource) {
97
+ sp = getEncodedTenantProduct(resource);
98
+ if (sp === null) {
99
+ oidcParams.resource = resource;
100
+ }
101
+ }
102
+ if (!sp && requestedScopes) {
103
+ const encodedParams = requestedScopes.find((scope) => scope.includes('=') && scope.includes('&')); // for now assume only one encoded param i.e. for tenant/product
104
+ if (encodedParams) {
105
+ sp = getEncodedTenantProduct(encodedParams);
106
+ }
107
+ }
108
+ if (sp && sp.tenant && sp.product) {
109
+ const { tenant, product } = sp;
110
+ requestedTenant = tenant;
111
+ requestedProduct = product;
112
+ const response = yield this.ssoHandler.resolveConnection({
113
+ tenant,
114
+ product,
115
+ idp_hint,
116
+ authFlow: 'oauth',
117
+ originalParams: Object.assign({}, body),
118
+ });
119
+ if ('redirectUrl' in response) {
120
+ return {
121
+ redirect_url: response.redirectUrl,
122
+ };
123
+ }
124
+ if ('connection' in response) {
125
+ connection = response.connection;
126
+ }
127
+ }
128
+ else {
129
+ // client_id is not encoded, so we look for the connection using the client_id
130
+ // First we check if it's a federated connection
131
+ if (client_id.startsWith(`${clientIDFederatedPrefix}${clientIDOIDCPrefix}`)) {
132
+ isOIDCFederated = true;
133
+ fedApp = yield this.idFedApp.get({
134
+ id: client_id.replace(clientIDFederatedPrefix, ''),
135
+ });
136
+ const response = yield this.ssoHandler.resolveConnection({
137
+ tenant: fedApp.tenant,
138
+ product: fedApp.product,
139
+ idp_hint,
140
+ authFlow: 'oauth',
141
+ originalParams: Object.assign({}, body),
142
+ tenants: fedApp.tenants,
143
+ idFedAppId: fedApp.id,
144
+ fedType: fedApp.type,
145
+ });
146
+ if ('redirectUrl' in response) {
147
+ return {
148
+ redirect_url: response.redirectUrl,
149
+ };
150
+ }
151
+ if ('connection' in response) {
152
+ connection = response.connection;
153
+ requestedTenant = fedApp.tenant;
154
+ requestedProduct = fedApp.product;
155
+ }
156
+ }
157
+ else {
158
+ // If it's not a federated connection, we look for the connection using the client_id
159
+ connection = yield this.connectionStore.get(client_id);
160
+ if (connection) {
161
+ requestedTenant = connection.tenant;
162
+ requestedProduct = connection.product;
163
+ }
164
+ }
165
+ }
166
+ }
167
+ else {
168
+ throw new JacksonError('You need to specify client_id or tenant & product', 403);
169
+ }
170
+ if (!connection) {
171
+ throw new JacksonError('IdP connection not found.', 403);
172
+ }
173
+ if (!allowed.redirect(redirect_uri, connection.redirectUrl)) {
174
+ if (fedApp) {
175
+ if (!allowed.redirect(redirect_uri, fedApp.redirectUrl)) {
176
+ throw new JacksonError('Redirect URL is not allowed.', 403);
177
+ }
178
+ }
179
+ else {
180
+ throw new JacksonError('Redirect URL is not allowed.', 403);
181
+ }
182
+ }
183
+ if (!isConnectionActive(connection)) {
184
+ throw new JacksonError('SSO connection is deactivated. Please contact your administrator.', 403);
185
+ }
186
+ }
187
+ catch (err) {
188
+ const error_description = getErrorMessage(err);
189
+ // Save the error trace
190
+ yield this.ssoTraces.saveTrace({
191
+ error: error_description,
192
+ context: {
193
+ tenant: requestedTenant || '',
194
+ product: requestedProduct || '',
195
+ clientID: (connection === null || connection === void 0 ? void 0 : connection.clientID) || '',
196
+ requestedOIDCFlow,
197
+ isOIDCFederated,
198
+ redirectUri: redirect_uri,
199
+ },
200
+ });
201
+ throw err;
202
+ }
203
+ const isMissingJWTKeysForOIDCFlow = requestedOIDCFlow &&
204
+ (!((_a = this.opts.openid) === null || _a === void 0 ? void 0 : _a.jwtSigningKeys) || !isJWSKeyPairLoaded(this.opts.openid.jwtSigningKeys));
205
+ const oAuthClientReqError = !state || response_type !== 'code';
206
+ const connectionIsSAML = 'idpMetadata' in connection && connection.idpMetadata !== undefined;
207
+ const connectionIsOIDC = 'oidcProvider' in connection && connection.oidcProvider !== undefined;
208
+ if (isMissingJWTKeysForOIDCFlow || oAuthClientReqError || (!connectionIsSAML && !connectionIsOIDC)) {
209
+ let error, error_description;
210
+ if (isMissingJWTKeysForOIDCFlow) {
211
+ error = 'server_error';
212
+ error_description =
213
+ 'OAuth server not configured correctly for openid flow, check if JWT signing keys are loaded';
214
+ }
215
+ if (!state) {
216
+ error = 'invalid_request';
217
+ error_description = 'Please specify a state to safeguard against XSRF attacks';
218
+ }
219
+ if (response_type !== 'code') {
220
+ error = 'unsupported_response_type';
221
+ error_description = 'Only Authorization Code grant is supported';
222
+ }
223
+ if (!connectionIsSAML && !connectionIsOIDC) {
224
+ error = 'server_error';
225
+ error_description = 'Connection appears to be misconfigured';
226
+ }
227
+ // Save the error trace
228
+ const traceId = yield this.ssoTraces.saveTrace({
229
+ error: error_description,
230
+ context: {
231
+ tenant: requestedTenant,
232
+ product: requestedProduct,
233
+ clientID: connection.clientID,
234
+ requestedOIDCFlow,
235
+ isOIDCFederated,
236
+ redirectUri: redirect_uri,
237
+ },
238
+ });
239
+ return {
240
+ redirect_url: OAuthErrorResponse({
241
+ error,
242
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
243
+ redirect_uri,
244
+ state,
245
+ }),
246
+ };
247
+ }
248
+ // Connection retrieved: Handover to IdP starts here
249
+ let ssoUrl;
250
+ let post = false;
251
+ // Init sessionId
252
+ const sessionId = crypto.randomBytes(16).toString('hex');
253
+ const relayState = relayStatePrefix + sessionId;
254
+ // SAML connection: SAML request will be constructed here
255
+ let samlReq;
256
+ if (connectionIsSAML) {
257
+ try {
258
+ const { sso } = connection.idpMetadata;
259
+ if ('redirectUrl' in sso) {
260
+ // HTTP Redirect binding
261
+ ssoUrl = sso.redirectUrl;
262
+ }
263
+ else if ('postUrl' in sso) {
264
+ // HTTP-POST binding
265
+ ssoUrl = sso.postUrl;
266
+ post = true;
267
+ }
268
+ else {
269
+ // This code here is kept for backward compatibility. We now have validation while adding the SSO connection to ensure binding is present.
270
+ const error_description = 'SAML binding could not be retrieved';
271
+ // Save the error trace
272
+ const traceId = yield this.ssoTraces.saveTrace({
273
+ error: error_description,
274
+ context: {
275
+ tenant: requestedTenant,
276
+ product: requestedProduct,
277
+ clientID: connection.clientID,
278
+ requestedOIDCFlow,
279
+ isOIDCFederated,
280
+ redirectUri: redirect_uri,
281
+ },
282
+ });
283
+ return {
284
+ redirect_url: OAuthErrorResponse({
285
+ error: 'invalid_request',
286
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
287
+ redirect_uri,
288
+ state,
289
+ }),
290
+ };
291
+ }
292
+ const cert = yield getDefaultCertificate();
293
+ samlReq = saml.request({
294
+ ssoUrl,
295
+ entityID: this.opts.samlAudience,
296
+ callbackUrl: this.opts.externalUrl + this.opts.samlPath,
297
+ signingKey: cert.privateKey,
298
+ publicKey: cert.publicKey,
299
+ forceAuthn: forceAuthn === 'true' ? true : !!connection.forceAuthn,
300
+ identifierFormat: connection.identifierFormat
301
+ ? connection.identifierFormat
302
+ : 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
303
+ });
304
+ }
305
+ catch (err) {
306
+ const error_description = getErrorMessage(err);
307
+ // Save the error trace
308
+ const traceId = yield this.ssoTraces.saveTrace({
309
+ error: error_description,
310
+ context: {
311
+ tenant: requestedTenant,
312
+ product: requestedProduct,
313
+ clientID: connection.clientID,
314
+ requestedOIDCFlow,
315
+ isOIDCFederated,
316
+ redirectUri: redirect_uri,
317
+ },
318
+ });
319
+ return {
320
+ redirect_url: OAuthErrorResponse({
321
+ error: 'server_error',
322
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
323
+ redirect_uri,
324
+ state,
325
+ }),
326
+ };
327
+ }
328
+ }
329
+ // OIDC Connection: Issuer discovery, openid-client init and extraction of authorization endpoint happens here
330
+ let oidcCodeVerifier;
331
+ let oidcNonce;
332
+ if (connectionIsOIDC) {
333
+ const { discoveryUrl, metadata, clientId, clientSecret } = connection.oidcProvider;
334
+ const { ssoTraces } = this;
335
+ try {
336
+ if (!this.opts.oidcPath) {
337
+ throw new JacksonError('OpenID response handler path (oidcPath) is not set');
338
+ }
339
+ const client = yield import('openid-client');
340
+ const oidcConfig = yield oidcClientConfig({
341
+ discoveryUrl,
342
+ metadata,
343
+ clientId,
344
+ clientSecret,
345
+ ssoTraces: {
346
+ instance: ssoTraces,
347
+ context: {
348
+ tenant: requestedTenant,
349
+ product: requestedProduct,
350
+ clientID: connection.clientID,
351
+ requestedOIDCFlow,
352
+ isOIDCFederated,
353
+ redirectUri: redirect_uri,
354
+ },
355
+ },
356
+ });
357
+ oidcCodeVerifier = client.randomPKCECodeVerifier();
358
+ const code_challenge = yield client.calculatePKCECodeChallenge(oidcCodeVerifier);
359
+ oidcNonce = client.randomNonce();
360
+ const standardScopes = ((_b = this.opts.openid) === null || _b === void 0 ? void 0 : _b.requestProfileScope)
361
+ ? ['openid', 'email', 'profile']
362
+ : ['openid', 'email'];
363
+ const paramsToForward = ((_c = this.opts.openid) === null || _c === void 0 ? void 0 : _c.forwardOIDCParams) ? oidcParams : {};
364
+ if (login_hint) {
365
+ paramsToForward.login_hint = login_hint;
366
+ }
367
+ ssoUrl = client.buildAuthorizationUrl(oidcConfig, Object.assign({ scope: [...requestedScopes, ...standardScopes]
368
+ .filter((value, index, self) => self.indexOf(value) === index) // filter out duplicates
369
+ .join(' '), code_challenge, code_challenge_method: 'S256', state: relayState, nonce: oidcNonce, redirect_uri: this.opts.externalUrl + this.opts.oidcPath }, paramsToForward)).href;
370
+ }
371
+ catch (err) {
372
+ const error_description = getErrorMessage(err);
373
+ // Save the error trace
374
+ const traceId = yield this.ssoTraces.saveTrace({
375
+ error: error_description,
376
+ context: {
377
+ tenant: requestedTenant,
378
+ product: requestedProduct,
379
+ clientID: connection.clientID,
380
+ requestedOIDCFlow,
381
+ isOIDCFederated,
382
+ redirectUri: redirect_uri,
383
+ },
384
+ });
385
+ if (err) {
386
+ return {
387
+ redirect_url: OAuthErrorResponse({
388
+ error: 'server_error',
389
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
390
+ redirect_uri,
391
+ state,
392
+ }),
393
+ };
394
+ }
395
+ }
396
+ }
397
+ // Session persistence happens here
398
+ try {
399
+ const requested = { client_id, state, redirect_uri };
400
+ if (requestedTenant) {
401
+ requested.tenant = requestedTenant;
402
+ }
403
+ if (requestedProduct) {
404
+ requested.product = requestedProduct;
405
+ }
406
+ if (idp_hint) {
407
+ requested.idp_hint = idp_hint;
408
+ }
409
+ else {
410
+ if (fedApp) {
411
+ requested.idp_hint = connection.clientID;
412
+ }
413
+ }
414
+ if (requestedOIDCFlow) {
415
+ requested.oidc = true;
416
+ if (nonce) {
417
+ requested.nonce = nonce;
418
+ }
419
+ }
420
+ if (requestedScopes) {
421
+ requested.scope = requestedScopes;
422
+ }
423
+ const sessionObj = {
424
+ redirect_uri,
425
+ response_type,
426
+ state,
427
+ code_challenge,
428
+ code_challenge_method,
429
+ requested,
430
+ oidcFederated: fedApp
431
+ ? {
432
+ redirectUrl: fedApp.redirectUrl,
433
+ id: fedApp.id,
434
+ clientID: fedApp.clientID,
435
+ clientSecret: fedApp.clientSecret,
436
+ }
437
+ : undefined,
438
+ };
439
+ yield this.sessionStore.put(sessionId, connectionIsSAML
440
+ ? Object.assign(Object.assign({}, sessionObj), { id: samlReq === null || samlReq === void 0 ? void 0 : samlReq.id }) : Object.assign(Object.assign({}, sessionObj), { id: connection.clientID, oidcCodeVerifier, oidcNonce }));
441
+ // Redirect to IdP
442
+ if (connectionIsSAML) {
443
+ let redirectUrl;
444
+ let authorizeForm;
445
+ if (!post) {
446
+ // HTTP Redirect binding
447
+ redirectUrl = redirect.success(ssoUrl, {
448
+ RelayState: relayState,
449
+ SAMLRequest: Buffer.from(yield deflateRawAsync(samlReq.request)).toString('base64'),
450
+ });
451
+ }
452
+ else {
453
+ // HTTP POST binding
454
+ authorizeForm = saml.createPostForm(ssoUrl, [
455
+ {
456
+ name: 'RelayState',
457
+ value: relayState,
458
+ },
459
+ {
460
+ name: 'SAMLRequest',
461
+ value: Buffer.from(samlReq.request).toString('base64'),
462
+ },
463
+ ]);
464
+ }
465
+ return {
466
+ redirect_url: redirectUrl,
467
+ authorize_form: authorizeForm,
468
+ };
469
+ }
470
+ if (connectionIsOIDC) {
471
+ return { redirect_url: ssoUrl };
472
+ }
473
+ throw 'Connection appears to be misconfigured';
474
+ }
475
+ catch (err) {
476
+ const error_description = getErrorMessage(err);
477
+ // Save the error trace
478
+ const traceId = yield this.ssoTraces.saveTrace({
479
+ error: error_description,
480
+ context: {
481
+ tenant: requestedTenant,
482
+ product: requestedProduct,
483
+ clientID: connection.clientID,
484
+ requestedOIDCFlow,
485
+ isOIDCFederated,
486
+ redirectUri: redirect_uri,
487
+ samlRequest: (samlReq === null || samlReq === void 0 ? void 0 : samlReq.request) || '',
488
+ },
489
+ });
490
+ return {
491
+ redirect_url: OAuthErrorResponse({
492
+ error: 'server_error',
493
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
494
+ redirect_uri,
495
+ state,
496
+ }),
497
+ };
498
+ }
499
+ });
500
+ }
501
+ samlResponse(body) {
502
+ return __awaiter(this, void 0, void 0, function* () {
503
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
504
+ let connection;
505
+ let rawResponse;
506
+ let sessionId;
507
+ let session;
508
+ let issuer;
509
+ let isIdPFlow;
510
+ let isSAMLFederated;
511
+ let isOIDCFederated;
512
+ let validateOpts;
513
+ let redirect_uri;
514
+ const { SAMLResponse, idp_hint, RelayState = '' } = body;
515
+ try {
516
+ isIdPFlow = !RelayState.startsWith(relayStatePrefix);
517
+ rawResponse = Buffer.from(SAMLResponse, 'base64').toString();
518
+ issuer = saml.parseIssuer(rawResponse);
519
+ if (!this.opts.idpEnabled && isIdPFlow) {
520
+ // IdP login is disabled so block the request
521
+ throw new JacksonError('IdP (Identity Provider) flow has been disabled. Please head to your Service Provider to login.', 403);
522
+ }
523
+ sessionId = RelayState.replace(relayStatePrefix, '');
524
+ if (!issuer) {
525
+ throw new JacksonError('Issuer not found.', 403);
526
+ }
527
+ const connections = (yield this.connectionStore.getByIndex({
528
+ name: IndexNames.EntityID,
529
+ value: issuer,
530
+ })).data;
531
+ if (!connections || connections.length === 0) {
532
+ throw new JacksonError('SAML connection not found.', 403);
533
+ }
534
+ session = sessionId ? yield this.sessionStore.get(sessionId) : null;
535
+ if (!isIdPFlow && !session) {
536
+ throw new JacksonError('Unable to validate state from the origin request.', 403);
537
+ }
538
+ isSAMLFederated = session && 'samlFederated' in session;
539
+ isOIDCFederated = session && 'oidcFederated' in session;
540
+ const isSPFlow = !isIdPFlow && !isSAMLFederated;
541
+ // IdP initiated SSO flow
542
+ if (isIdPFlow) {
543
+ const response = yield this.ssoHandler.resolveConnection({
544
+ idp_hint,
545
+ authFlow: 'idp-initiated',
546
+ entityId: issuer,
547
+ originalParams: {
548
+ SAMLResponse,
549
+ },
550
+ });
551
+ // Redirect to the product selection page
552
+ if ('postForm' in response) {
553
+ return {
554
+ app_select_form: response.postForm,
555
+ };
556
+ }
557
+ // Found a connection
558
+ if ('connection' in response) {
559
+ connection = response.connection;
560
+ if (!isConnectionActive(connection)) {
561
+ throw new JacksonError('SSO connection is deactivated. Please contact your administrator.', 403);
562
+ }
563
+ }
564
+ }
565
+ // SP initiated SSO flow
566
+ // Resolve if there are multiple matches for SP login
567
+ if (isSPFlow || isSAMLFederated || isOIDCFederated) {
568
+ connection = connections.filter((c) => {
569
+ return (c.clientID === session.requested.client_id ||
570
+ c.clientID === session.requested.idp_hint ||
571
+ (c.tenant === session.requested.tenant && c.product === session.requested.product));
572
+ })[0];
573
+ }
574
+ if (!connection) {
575
+ throw new JacksonError('SAML connection not found.', 403);
576
+ }
577
+ if (session &&
578
+ session.redirect_uri &&
579
+ !allowed.redirect(session.redirect_uri, connection.redirectUrl)) {
580
+ if (isOIDCFederated) {
581
+ if (!allowed.redirect(session.redirect_uri, (_a = session.oidcFederated) === null || _a === void 0 ? void 0 : _a.redirectUrl)) {
582
+ throw new JacksonError('Redirect URL is not allowed.', 403);
583
+ }
584
+ }
585
+ else {
586
+ throw new JacksonError('Redirect URL is not allowed.', 403);
587
+ }
588
+ }
589
+ const { privateKey } = yield getDefaultCertificate();
590
+ validateOpts = {
591
+ audience: `${this.opts.samlAudience}`,
592
+ privateKey,
593
+ };
594
+ if (connection.idpMetadata.publicKey) {
595
+ validateOpts.publicKey = connection.idpMetadata.publicKey;
596
+ }
597
+ else if (connection.idpMetadata.thumbprint) {
598
+ validateOpts.thumbprint = connection.idpMetadata.thumbprint;
599
+ }
600
+ if (session && session.id) {
601
+ validateOpts['inResponseTo'] = session.id;
602
+ }
603
+ redirect_uri = (session && session.redirect_uri) || connection.defaultRedirectUrl;
604
+ }
605
+ catch (err) {
606
+ // Save the error trace
607
+ yield this.ssoTraces.saveTrace({
608
+ error: getErrorMessage(err),
609
+ context: {
610
+ samlResponse: rawResponse,
611
+ tenant: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.tenant) || (connection === null || connection === void 0 ? void 0 : connection.tenant),
612
+ product: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.product) || (connection === null || connection === void 0 ? void 0 : connection.product),
613
+ clientID: ((_d = session === null || session === void 0 ? void 0 : session.requested) === null || _d === void 0 ? void 0 : _d.client_id) || (connection === null || connection === void 0 ? void 0 : connection.clientID),
614
+ providerName: (_e = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _e === void 0 ? void 0 : _e.provider,
615
+ redirectUri: isIdPFlow ? connection === null || connection === void 0 ? void 0 : connection.defaultRedirectUrl : session === null || session === void 0 ? void 0 : session.redirect_uri,
616
+ issuer,
617
+ isSAMLFederated,
618
+ isOIDCFederated,
619
+ isIdPFlow,
620
+ requestedOIDCFlow: !!((_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.oidc),
621
+ acsUrl: (_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.acsUrl,
622
+ entityId: (_h = session === null || session === void 0 ? void 0 : session.requested) === null || _h === void 0 ? void 0 : _h.entityId,
623
+ relayState: RelayState,
624
+ },
625
+ });
626
+ throw err; // Rethrow the error
627
+ }
628
+ let profile;
629
+ try {
630
+ profile = yield extractSAMLResponseAttributes(rawResponse, validateOpts);
631
+ // This is a federated SAML flow, let's create a new SAMLResponse and POST it to the SP
632
+ if (isSAMLFederated) {
633
+ const { responseForm } = yield this.ssoHandler.createSAMLResponse({ profile, session });
634
+ yield this.sessionStore.delete(sessionId);
635
+ return { response_form: responseForm };
636
+ }
637
+ const code = yield this._buildAuthorizationCode(connection, profile, session, isIdPFlow);
638
+ const params = {
639
+ code,
640
+ };
641
+ if (session && session.state) {
642
+ params['state'] = session.state;
643
+ }
644
+ yield this.sessionStore.delete(sessionId);
645
+ return { redirect_url: redirect.success(redirect_uri, params) };
646
+ }
647
+ catch (err) {
648
+ const error_description = getErrorMessage(err);
649
+ // Trace the error
650
+ const traceId = yield this.ssoTraces.saveTrace({
651
+ error: error_description,
652
+ context: {
653
+ samlResponse: rawResponse,
654
+ tenant: connection.tenant,
655
+ product: connection.product,
656
+ clientID: connection.clientID,
657
+ providerName: (_j = connection === null || connection === void 0 ? void 0 : connection.idpMetadata) === null || _j === void 0 ? void 0 : _j.provider,
658
+ redirectUri: isIdPFlow ? connection === null || connection === void 0 ? void 0 : connection.defaultRedirectUrl : session === null || session === void 0 ? void 0 : session.redirect_uri,
659
+ isSAMLFederated,
660
+ isOIDCFederated,
661
+ isIdPFlow,
662
+ acsUrl: (_k = session === null || session === void 0 ? void 0 : session.requested) === null || _k === void 0 ? void 0 : _k.acsUrl,
663
+ entityId: (_l = session === null || session === void 0 ? void 0 : session.requested) === null || _l === void 0 ? void 0 : _l.entityId,
664
+ requestedOIDCFlow: !!((_m = session === null || session === void 0 ? void 0 : session.requested) === null || _m === void 0 ? void 0 : _m.oidc),
665
+ relayState: RelayState,
666
+ issuer,
667
+ profile,
668
+ },
669
+ });
670
+ if (isSAMLFederated) {
671
+ throw err;
672
+ }
673
+ return {
674
+ redirect_url: OAuthErrorResponse({
675
+ error: 'access_denied',
676
+ error_description: traceId ? `${traceId}: ${error_description}` : error_description,
677
+ redirect_uri,
678
+ state: (_o = session === null || session === void 0 ? void 0 : session.requested) === null || _o === void 0 ? void 0 : _o.state,
679
+ }),
680
+ };
681
+ }
682
+ });
683
+ }
684
+ oidcAuthzResponse(body) {
685
+ return __awaiter(this, void 0, void 0, function* () {
686
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
687
+ let oidcConnection;
688
+ let session;
689
+ let isSAMLFederated;
690
+ let isOIDCFederated;
691
+ let redirect_uri;
692
+ let profile;
693
+ const callbackParams = body;
694
+ let RelayState = callbackParams.state || '';
695
+ try {
696
+ if (!RelayState) {
697
+ throw new JacksonError('State from original request is missing.', 403);
698
+ }
699
+ RelayState = RelayState.replace(relayStatePrefix, '');
700
+ session = yield this.sessionStore.get(RelayState);
701
+ if (!session) {
702
+ throw new JacksonError('Unable to validate state from the original request.', 403);
703
+ }
704
+ isSAMLFederated = session && 'samlFederated' in session;
705
+ isOIDCFederated = session && 'oidcFederated' in session;
706
+ oidcConnection = yield this.connectionStore.get(session.id);
707
+ if (!oidcConnection) {
708
+ throw new JacksonError('OIDC connection not found.', 403);
709
+ }
710
+ if (!isSAMLFederated) {
711
+ redirect_uri = session && session.redirect_uri;
712
+ if (!redirect_uri) {
713
+ throw new JacksonError('Redirect URL from the authorization request could not be retrieved', 403);
714
+ }
715
+ if (redirect_uri && !allowed.redirect(redirect_uri, oidcConnection.redirectUrl)) {
716
+ if (isOIDCFederated) {
717
+ if (!allowed.redirect(redirect_uri, (_a = session.oidcFederated) === null || _a === void 0 ? void 0 : _a.redirectUrl)) {
718
+ throw new JacksonError('Redirect URL is not allowed.', 403);
719
+ }
720
+ }
721
+ else {
722
+ throw new JacksonError('Redirect URL is not allowed.', 403);
723
+ }
724
+ }
725
+ }
726
+ }
727
+ catch (err) {
728
+ yield this.ssoTraces.saveTrace({
729
+ error: getErrorMessage(err),
730
+ context: {
731
+ tenant: ((_b = session === null || session === void 0 ? void 0 : session.requested) === null || _b === void 0 ? void 0 : _b.tenant) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.tenant),
732
+ product: ((_c = session === null || session === void 0 ? void 0 : session.requested) === null || _c === void 0 ? void 0 : _c.product) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.product),
733
+ clientID: ((_d = session === null || session === void 0 ? void 0 : session.requested) === null || _d === void 0 ? void 0 : _d.client_id) || (oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.clientID),
734
+ providerName: (_e = oidcConnection === null || oidcConnection === void 0 ? void 0 : oidcConnection.oidcProvider) === null || _e === void 0 ? void 0 : _e.provider,
735
+ acsUrl: (_f = session === null || session === void 0 ? void 0 : session.requested) === null || _f === void 0 ? void 0 : _f.acsUrl,
736
+ entityId: (_g = session === null || session === void 0 ? void 0 : session.requested) === null || _g === void 0 ? void 0 : _g.entityId,
737
+ redirectUri: redirect_uri,
738
+ relayState: RelayState,
739
+ isSAMLFederated,
740
+ isOIDCFederated,
741
+ requestedOIDCFlow: !!((_h = session === null || session === void 0 ? void 0 : session.requested) === null || _h === void 0 ? void 0 : _h.oidc),
742
+ oidcIdPRequest: (_j = session === null || session === void 0 ? void 0 : session.requested) === null || _j === void 0 ? void 0 : _j.oidcIdPRequest,
743
+ },
744
+ });
745
+ // Rethrow err and redirect to Jackson error page
746
+ throw err;
747
+ }
748
+ // Reconstruct the oidcClient, code exchange for token and user profile happens here
749
+ const { discoveryUrl, metadata, clientId, clientSecret } = oidcConnection.oidcProvider;
750
+ const { ssoTraces } = this;
751
+ let tokens = undefined;
752
+ try {
753
+ const client = yield import('openid-client');
754
+ const oidcConfig = yield oidcClientConfig({
755
+ discoveryUrl,
756
+ metadata,
757
+ clientId,
758
+ clientSecret,
759
+ ssoTraces: {
760
+ instance: ssoTraces,
761
+ context: {
762
+ tenant: oidcConnection.tenant,
763
+ product: oidcConnection.product,
764
+ clientID: oidcConnection.clientID,
765
+ providerName: oidcConnection.oidcProvider.provider,
766
+ redirectUri: redirect_uri,
767
+ relayState: RelayState,
768
+ isSAMLFederated,
769
+ isOIDCFederated,
770
+ acsUrl: session.requested.acsUrl,
771
+ entityId: session.requested.entityId,
772
+ requestedOIDCFlow: !!session.requested.oidc,
773
+ oidcIdPRequest: (_k = session === null || session === void 0 ? void 0 : session.requested) === null || _k === void 0 ? void 0 : _k.oidcIdPRequest,
774
+ },
775
+ },
776
+ });
777
+ const currentUrl = new URL(this.opts.externalUrl + this.opts.oidcPath + '?' + new URLSearchParams(callbackParams));
778
+ tokens = yield client.authorizationCodeGrant(oidcConfig, currentUrl, {
779
+ pkceCodeVerifier: session.oidcCodeVerifier,
780
+ expectedNonce: session.oidcNonce,
781
+ expectedState: callbackParams.state,
782
+ idTokenExpected: true,
783
+ });
784
+ profile = yield extractOIDCUserProfile(tokens, oidcConfig);
785
+ if (isSAMLFederated) {
786
+ const { responseForm } = yield this.ssoHandler.createSAMLResponse({ profile, session });
787
+ yield this.sessionStore.delete(RelayState);
788
+ return { response_form: responseForm };
789
+ }
790
+ const code = yield this._buildAuthorizationCode(oidcConnection, profile, session, false);
791
+ const params = {
792
+ code,
793
+ };
794
+ if (session && session.state) {
795
+ params['state'] = session.state;
796
+ }
797
+ yield this.sessionStore.delete(RelayState);
798
+ return { redirect_url: redirect.success(redirect_uri, params) };
799
+ }
800
+ catch (err) {
801
+ const { error, error_description, error_uri, session_state, scope, stack } = err;
802
+ const error_message = error_description || getErrorMessage(err);
803
+ const traceId = yield this.ssoTraces.saveTrace({
804
+ error: error_message,
805
+ context: {
806
+ tenant: oidcConnection.tenant,
807
+ product: oidcConnection.product,
808
+ clientID: oidcConnection.clientID,
809
+ providerName: oidcConnection.oidcProvider.provider,
810
+ redirectUri: redirect_uri,
811
+ relayState: RelayState,
812
+ isSAMLFederated,
813
+ isOIDCFederated,
814
+ acsUrl: session.requested.acsUrl,
815
+ entityId: session.requested.entityId,
816
+ requestedOIDCFlow: !!session.requested.oidc,
817
+ oidcIdPRequest: (_l = session === null || session === void 0 ? void 0 : session.requested) === null || _l === void 0 ? void 0 : _l.oidcIdPRequest,
818
+ profile,
819
+ error,
820
+ error_description,
821
+ error_uri,
822
+ session_state_from_op_error: session_state,
823
+ scope_from_op_error: scope,
824
+ stack,
825
+ oidcTokenSet: { id_token: tokens === null || tokens === void 0 ? void 0 : tokens.id_token, access_token: tokens === null || tokens === void 0 ? void 0 : tokens.access_token },
826
+ },
827
+ });
828
+ if (isSAMLFederated) {
829
+ throw err;
830
+ }
831
+ return {
832
+ redirect_url: OAuthErrorResponse({
833
+ error: error || 'server_error',
834
+ error_description: traceId ? `${traceId}: ${error_message}` : error_message,
835
+ redirect_uri: redirect_uri,
836
+ state: session.state,
837
+ }),
838
+ };
839
+ }
840
+ });
841
+ }
842
+ // Build the authorization code for the session
843
+ _buildAuthorizationCode(connection, profile, session, isIdPFlow) {
844
+ return __awaiter(this, void 0, void 0, function* () {
845
+ // Store details against a code
846
+ const code = crypto.randomBytes(20).toString('hex');
847
+ const requested = isIdPFlow
848
+ ? { isIdPFlow: true, tenant: connection.tenant, product: connection.product }
849
+ : session
850
+ ? session.requested
851
+ : null;
852
+ const codeVal = {
853
+ profile,
854
+ clientID: connection.clientID,
855
+ clientSecret: connection.clientSecret,
856
+ requested,
857
+ isIdPFlow,
858
+ };
859
+ if (session) {
860
+ codeVal['session'] = session;
861
+ }
862
+ yield this.codeStore.put(code, codeVal);
863
+ return code;
864
+ });
865
+ }
866
+ /**
867
+ * @swagger
868
+ *
869
+ * /oauth/token:
870
+ * post:
871
+ * summary: Code exchange
872
+ * operationId: oauth-code-exchange
873
+ * tags:
874
+ * - OAuth
875
+ * consumes:
876
+ * - application/x-www-form-urlencoded
877
+ * parameters:
878
+ * - name: grant_type
879
+ * in: formData
880
+ * type: string
881
+ * description: Grant type should be 'authorization_code'
882
+ * default: authorization_code
883
+ * required: true
884
+ * - name: client_id
885
+ * in: formData
886
+ * type: string
887
+ * description: Use the client_id returned by the SAML connection API
888
+ * required: true
889
+ * - name: client_secret
890
+ * in: formData
891
+ * type: string
892
+ * description: Use the client_secret returned by the SAML connection API
893
+ * required: true
894
+ * - name: code_verifier
895
+ * in: formData
896
+ * type: string
897
+ * description: code_verifier against the code_challenge in the authz request (relevant to PKCE flow)
898
+ * - name: redirect_uri
899
+ * in: formData
900
+ * type: string
901
+ * description: Redirect URI
902
+ * required: true
903
+ * - name: code
904
+ * in: formData
905
+ * type: string
906
+ * description: Code
907
+ * required: true
908
+ * responses:
909
+ * '200':
910
+ * description: Success
911
+ * schema:
912
+ * type: object
913
+ * properties:
914
+ * access_token:
915
+ * type: string
916
+ * token_type:
917
+ * type: string
918
+ * expires_in:
919
+ * type: string
920
+ * example:
921
+ * access_token: 8958e13053832b5af58fdf2ee83f35f5d013dc74
922
+ * token_type: bearer
923
+ * expires_in: 300
924
+ */
925
+ token(body, authHeader) {
926
+ return __awaiter(this, void 0, void 0, function* () {
927
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
928
+ let basic_client_id;
929
+ let basic_client_secret;
930
+ try {
931
+ if (authHeader) {
932
+ // Authorization: Basic {Base64(<client_id>:<client_secret>)}
933
+ const base64Credentials = authHeader.split(' ')[1];
934
+ const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
935
+ [basic_client_id, basic_client_secret] = credentials.split(':');
936
+ }
937
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
938
+ }
939
+ catch (err) {
940
+ // no-op
941
+ }
942
+ const { code, grant_type = 'authorization_code', redirect_uri } = body;
943
+ const client_id = 'client_id' in body ? body.client_id : basic_client_id;
944
+ const client_secret = 'client_secret' in body ? body.client_secret : basic_client_secret;
945
+ const code_verifier = 'code_verifier' in body ? body.code_verifier : undefined;
946
+ metrics.increment('oauthToken');
947
+ if (grant_type !== 'authorization_code') {
948
+ throw new JacksonError('Unsupported grant_type', 400);
949
+ }
950
+ if (!code) {
951
+ throw new JacksonError('Please specify code', 400);
952
+ }
953
+ const codeVal = yield this.codeStore.get(code);
954
+ if (!codeVal || !codeVal.profile) {
955
+ throw new JacksonError('Invalid code', 403);
956
+ }
957
+ if ((_a = codeVal.requested) === null || _a === void 0 ? void 0 : _a.redirect_uri) {
958
+ if (redirect_uri !== codeVal.requested.redirect_uri) {
959
+ throw new JacksonError(`Invalid request: ${!redirect_uri ? 'redirect_uri missing' : 'redirect_uri mismatch'}`, 400);
960
+ }
961
+ }
962
+ if (code_verifier) {
963
+ // PKCE flow
964
+ let cv = code_verifier;
965
+ if (((_b = codeVal.session.code_challenge_method) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === 's256') {
966
+ cv = codeVerifier.encode(code_verifier);
967
+ }
968
+ if (codeVal.session.code_challenge !== cv) {
969
+ throw new JacksonError('Invalid code_verifier', 401);
970
+ }
971
+ // For Federation flow, we need to verify the client_secret
972
+ if (client_id === null || client_id === void 0 ? void 0 : client_id.startsWith(`${clientIDFederatedPrefix}${clientIDOIDCPrefix}`)) {
973
+ if (client_id !== ((_d = (_c = codeVal.session) === null || _c === void 0 ? void 0 : _c.oidcFederated) === null || _d === void 0 ? void 0 : _d.clientID) ||
974
+ client_secret !== ((_f = (_e = codeVal.session) === null || _e === void 0 ? void 0 : _e.oidcFederated) === null || _f === void 0 ? void 0 : _f.clientSecret)) {
975
+ throw new JacksonError('Invalid client_id or client_secret', 401);
976
+ }
977
+ }
978
+ }
979
+ else if (client_id && client_secret) {
980
+ // check if we have an encoded client_id
981
+ if (client_id !== 'dummy') {
982
+ const sp = getEncodedTenantProduct(client_id);
983
+ if (!sp) {
984
+ // OAuth flow
985
+ if (client_id !== codeVal.clientID || client_secret !== codeVal.clientSecret) {
986
+ throw new JacksonError('Invalid client_id or client_secret', 401);
987
+ }
988
+ }
989
+ else {
990
+ if (!codeVal.isIdPFlow &&
991
+ (sp.tenant !== ((_g = codeVal.requested) === null || _g === void 0 ? void 0 : _g.tenant) || sp.product !== ((_h = codeVal.requested) === null || _h === void 0 ? void 0 : _h.product))) {
992
+ throw new JacksonError('Invalid tenant or product', 401);
993
+ }
994
+ // encoded client_id, verify client_secret
995
+ if (client_secret !== this.opts.clientSecretVerifier) {
996
+ throw new JacksonError('Invalid client_secret', 401);
997
+ }
998
+ }
999
+ }
1000
+ else {
1001
+ if (client_secret !== this.opts.clientSecretVerifier && client_secret !== codeVal.clientSecret) {
1002
+ throw new JacksonError('Invalid client_secret', 401);
1003
+ }
1004
+ }
1005
+ }
1006
+ else if (codeVal && codeVal.session) {
1007
+ throw new JacksonError('Please specify client_secret or code_verifier', 401);
1008
+ }
1009
+ // store details against a token
1010
+ const token = crypto.randomBytes(20).toString('hex');
1011
+ const tokenVal = Object.assign(Object.assign({}, codeVal.profile), { requested: codeVal.requested });
1012
+ const requestedOIDCFlow = !!((_j = codeVal.requested) === null || _j === void 0 ? void 0 : _j.oidc);
1013
+ const requestHasNonce = !!((_k = codeVal.requested) === null || _k === void 0 ? void 0 : _k.nonce);
1014
+ if (requestedOIDCFlow) {
1015
+ const { jwtSigningKeys, jwsAlg } = (_l = this.opts.openid) !== null && _l !== void 0 ? _l : {};
1016
+ if (!jwtSigningKeys || !isJWSKeyPairLoaded(jwtSigningKeys)) {
1017
+ throw new JacksonError('JWT signing keys are not loaded', 500);
1018
+ }
1019
+ let claims = requestHasNonce ? { nonce: codeVal.requested.nonce } : {};
1020
+ claims = Object.assign(Object.assign({}, claims), { id: codeVal.profile.claims.id, email: codeVal.profile.claims.email, firstName: codeVal.profile.claims.firstName, lastName: codeVal.profile.claims.lastName, roles: codeVal.profile.claims.roles, groups: codeVal.profile.claims.groups });
1021
+ const signingKey = yield loadJWSPrivateKey(jwtSigningKeys.private, jwsAlg);
1022
+ const kid = yield computeKid(jwtSigningKeys.public, jwsAlg);
1023
+ const id_token = yield new jose.SignJWT(claims)
1024
+ .setProtectedHeader({ alg: jwsAlg, kid })
1025
+ .setIssuedAt()
1026
+ .setIssuer(this.opts.externalUrl)
1027
+ .setSubject(codeVal.profile.claims.id)
1028
+ .setAudience(tokenVal.requested.client_id)
1029
+ .setExpirationTime(`${this.opts.db.ttl}s`) // identity token only really needs to be valid long enough for it to be verified by the client application.
1030
+ .sign(signingKey);
1031
+ tokenVal.id_token = id_token;
1032
+ tokenVal.claims.sub = codeVal.profile.claims.id;
1033
+ }
1034
+ yield this.tokenStore.put(token, tokenVal);
1035
+ // delete the code
1036
+ try {
1037
+ yield this.codeStore.delete(code);
1038
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1039
+ }
1040
+ catch (_err) {
1041
+ // ignore error
1042
+ }
1043
+ const tokenResponse = {
1044
+ access_token: token,
1045
+ token_type: 'bearer',
1046
+ expires_in: this.opts.db.ttl,
1047
+ };
1048
+ if (requestedOIDCFlow) {
1049
+ tokenResponse.id_token = tokenVal.id_token;
1050
+ }
1051
+ return tokenResponse;
1052
+ });
1053
+ }
1054
+ /**
1055
+ * @swagger
1056
+ *
1057
+ * /oauth/userinfo:
1058
+ * get:
1059
+ * summary: Get profile
1060
+ * operationId: oauth-get-profile
1061
+ * tags:
1062
+ * - OAuth
1063
+ * responses:
1064
+ * '200':
1065
+ * description: Success
1066
+ * schema:
1067
+ * type: object
1068
+ * properties:
1069
+ * id:
1070
+ * type: string
1071
+ * email:
1072
+ * type: string
1073
+ * firstName:
1074
+ * type: string
1075
+ * lastName:
1076
+ * type: string
1077
+ * roles:
1078
+ * type: array
1079
+ * items:
1080
+ * type: string
1081
+ * groups:
1082
+ * type: array
1083
+ * items:
1084
+ * type: string
1085
+ * raw:
1086
+ * type: object
1087
+ * requested:
1088
+ * type: object
1089
+ * example:
1090
+ * id: 32b5af58fdf
1091
+ * email: jackson@coolstartup.com
1092
+ * firstName: SAML
1093
+ * lastName: Jackson
1094
+ * raw: {
1095
+ *
1096
+ * }
1097
+ * requested: {
1098
+ *
1099
+ * }
1100
+ */
1101
+ userInfo(token) {
1102
+ return __awaiter(this, void 0, void 0, function* () {
1103
+ const rsp = yield this.tokenStore.get(token);
1104
+ metrics.increment('oauthUserInfo');
1105
+ if (!rsp || !rsp.claims) {
1106
+ throw new JacksonError('Invalid token', 403);
1107
+ }
1108
+ return Object.assign(Object.assign({}, rsp.claims), { requested: rsp.requested });
1109
+ });
1110
+ }
1111
+ }
1112
+ //# sourceMappingURL=oauth.js.map