@budibase/backend-core 3.2.5 → 3.2.7

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 (276) hide show
  1. package/dist/index.js +7 -1
  2. package/dist/index.js.map +2 -2
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +11 -4
  5. package/dist/plugins.js.meta.json +1 -1
  6. package/dist/src/environment.d.ts +1 -0
  7. package/dist/src/environment.js +6 -1
  8. package/dist/src/environment.js.map +1 -1
  9. package/package.json +11 -4
  10. package/src/accounts/accounts.ts +0 -82
  11. package/src/accounts/api.ts +0 -59
  12. package/src/accounts/index.ts +0 -1
  13. package/src/auth/auth.ts +0 -210
  14. package/src/auth/index.ts +0 -1
  15. package/src/auth/tests/auth.spec.ts +0 -14
  16. package/src/blacklist/blacklist.ts +0 -54
  17. package/src/blacklist/index.ts +0 -1
  18. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  19. package/src/cache/appMetadata.ts +0 -88
  20. package/src/cache/base/index.ts +0 -150
  21. package/src/cache/docWritethrough.ts +0 -105
  22. package/src/cache/generic.ts +0 -33
  23. package/src/cache/index.ts +0 -8
  24. package/src/cache/invite.ts +0 -86
  25. package/src/cache/passwordReset.ts +0 -49
  26. package/src/cache/tests/docWritethrough.spec.ts +0 -296
  27. package/src/cache/tests/user.spec.ts +0 -145
  28. package/src/cache/tests/writethrough.spec.ts +0 -139
  29. package/src/cache/user.ts +0 -154
  30. package/src/cache/writethrough.ts +0 -133
  31. package/src/configs/configs.ts +0 -263
  32. package/src/configs/index.ts +0 -1
  33. package/src/configs/tests/configs.spec.ts +0 -184
  34. package/src/constants/db.ts +0 -75
  35. package/src/constants/index.ts +0 -2
  36. package/src/constants/misc.ts +0 -36
  37. package/src/context/Context.ts +0 -14
  38. package/src/context/identity.ts +0 -58
  39. package/src/context/index.ts +0 -3
  40. package/src/context/mainContext.ts +0 -422
  41. package/src/context/tests/index.spec.ts +0 -255
  42. package/src/context/types.ts +0 -26
  43. package/src/db/Replication.ts +0 -94
  44. package/src/db/couch/DatabaseImpl.ts +0 -511
  45. package/src/db/couch/connections.ts +0 -89
  46. package/src/db/couch/index.ts +0 -4
  47. package/src/db/couch/pouchDB.ts +0 -97
  48. package/src/db/couch/pouchDump.ts +0 -0
  49. package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
  50. package/src/db/couch/utils.ts +0 -55
  51. package/src/db/db.ts +0 -34
  52. package/src/db/errors.ts +0 -14
  53. package/src/db/index.ts +0 -12
  54. package/src/db/instrumentation.ts +0 -199
  55. package/src/db/lucene.ts +0 -721
  56. package/src/db/searchIndexes/index.ts +0 -1
  57. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  58. package/src/db/tests/DatabaseImpl.spec.ts +0 -55
  59. package/src/db/tests/connections.spec.ts +0 -22
  60. package/src/db/tests/index.spec.ts +0 -32
  61. package/src/db/tests/lucene.spec.ts +0 -400
  62. package/src/db/tests/pouch.spec.js +0 -62
  63. package/src/db/tests/utils.spec.ts +0 -63
  64. package/src/db/utils.ts +0 -208
  65. package/src/db/views.ts +0 -245
  66. package/src/docIds/conversions.ts +0 -60
  67. package/src/docIds/ids.ts +0 -126
  68. package/src/docIds/index.ts +0 -2
  69. package/src/docIds/newid.ts +0 -5
  70. package/src/docIds/params.ts +0 -189
  71. package/src/docUpdates/index.ts +0 -24
  72. package/src/environment.ts +0 -293
  73. package/src/errors/errors.ts +0 -119
  74. package/src/errors/index.ts +0 -1
  75. package/src/events/analytics.ts +0 -6
  76. package/src/events/asyncEvents/index.ts +0 -2
  77. package/src/events/asyncEvents/publisher.ts +0 -12
  78. package/src/events/asyncEvents/queue.ts +0 -22
  79. package/src/events/backfill.ts +0 -183
  80. package/src/events/documentId.ts +0 -56
  81. package/src/events/events.ts +0 -47
  82. package/src/events/identification.ts +0 -311
  83. package/src/events/index.ts +0 -15
  84. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  85. package/src/events/processors/AuditLogsProcessor.ts +0 -92
  86. package/src/events/processors/LoggingProcessor.ts +0 -36
  87. package/src/events/processors/Processors.ts +0 -52
  88. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
  89. package/src/events/processors/index.ts +0 -19
  90. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  91. package/src/events/processors/posthog/index.ts +0 -3
  92. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  93. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
  94. package/src/events/processors/types.ts +0 -1
  95. package/src/events/publishers/account.ts +0 -41
  96. package/src/events/publishers/ai.ts +0 -21
  97. package/src/events/publishers/app.ts +0 -168
  98. package/src/events/publishers/auditLog.ts +0 -26
  99. package/src/events/publishers/auth.ts +0 -73
  100. package/src/events/publishers/automation.ts +0 -110
  101. package/src/events/publishers/backfill.ts +0 -74
  102. package/src/events/publishers/backup.ts +0 -42
  103. package/src/events/publishers/datasource.ts +0 -48
  104. package/src/events/publishers/email.ts +0 -17
  105. package/src/events/publishers/environmentVariable.ts +0 -38
  106. package/src/events/publishers/group.ts +0 -99
  107. package/src/events/publishers/index.ts +0 -25
  108. package/src/events/publishers/installation.ts +0 -38
  109. package/src/events/publishers/layout.ts +0 -26
  110. package/src/events/publishers/license.ts +0 -84
  111. package/src/events/publishers/org.ts +0 -37
  112. package/src/events/publishers/plugin.ts +0 -47
  113. package/src/events/publishers/query.ts +0 -89
  114. package/src/events/publishers/role.ts +0 -62
  115. package/src/events/publishers/rows.ts +0 -29
  116. package/src/events/publishers/screen.ts +0 -36
  117. package/src/events/publishers/serve.ts +0 -43
  118. package/src/events/publishers/table.ts +0 -70
  119. package/src/events/publishers/user.ts +0 -202
  120. package/src/events/publishers/view.ts +0 -107
  121. package/src/features/features.ts +0 -277
  122. package/src/features/index.ts +0 -2
  123. package/src/features/tests/features.spec.ts +0 -267
  124. package/src/features/tests/utils.ts +0 -64
  125. package/src/helpers.ts +0 -9
  126. package/src/index.ts +0 -59
  127. package/src/installation.ts +0 -115
  128. package/src/logging/alerts.ts +0 -26
  129. package/src/logging/correlation/correlation.ts +0 -15
  130. package/src/logging/correlation/index.ts +0 -1
  131. package/src/logging/correlation/middleware.ts +0 -18
  132. package/src/logging/index.ts +0 -4
  133. package/src/logging/pino/logger.ts +0 -239
  134. package/src/logging/pino/middleware.ts +0 -48
  135. package/src/logging/system.ts +0 -81
  136. package/src/logging/tests/system.spec.ts +0 -61
  137. package/src/middleware/adminOnly.ts +0 -9
  138. package/src/middleware/auditLog.ts +0 -6
  139. package/src/middleware/authenticated.ts +0 -247
  140. package/src/middleware/builderOnly.ts +0 -21
  141. package/src/middleware/builderOrAdmin.ts +0 -21
  142. package/src/middleware/contentSecurityPolicy.ts +0 -113
  143. package/src/middleware/csrf.ts +0 -81
  144. package/src/middleware/errorHandling.ts +0 -43
  145. package/src/middleware/index.ts +0 -24
  146. package/src/middleware/internalApi.ts +0 -23
  147. package/src/middleware/ip.ts +0 -12
  148. package/src/middleware/joi-validator.ts +0 -58
  149. package/src/middleware/matchers.ts +0 -39
  150. package/src/middleware/passport/datasource/google.ts +0 -102
  151. package/src/middleware/passport/local.ts +0 -54
  152. package/src/middleware/passport/sso/google.ts +0 -77
  153. package/src/middleware/passport/sso/oidc.ts +0 -152
  154. package/src/middleware/passport/sso/sso.ts +0 -138
  155. package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
  156. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
  157. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  158. package/src/middleware/passport/utils.ts +0 -38
  159. package/src/middleware/querystringToBody.ts +0 -28
  160. package/src/middleware/tenancy.ts +0 -36
  161. package/src/middleware/tests/builder.spec.ts +0 -181
  162. package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
  163. package/src/middleware/tests/matchers.spec.ts +0 -100
  164. package/src/migrations/definitions.ts +0 -40
  165. package/src/migrations/index.ts +0 -2
  166. package/src/migrations/migrations.ts +0 -186
  167. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  168. package/src/migrations/tests/migrations.spec.ts +0 -64
  169. package/src/objectStore/buckets/app.ts +0 -53
  170. package/src/objectStore/buckets/global.ts +0 -29
  171. package/src/objectStore/buckets/index.ts +0 -3
  172. package/src/objectStore/buckets/plugins.ts +0 -71
  173. package/src/objectStore/buckets/tests/app.spec.ts +0 -161
  174. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  175. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  176. package/src/objectStore/cloudfront.ts +0 -41
  177. package/src/objectStore/index.ts +0 -3
  178. package/src/objectStore/objectStore.ts +0 -585
  179. package/src/objectStore/utils.ts +0 -113
  180. package/src/platform/index.ts +0 -3
  181. package/src/platform/platformDb.ts +0 -6
  182. package/src/platform/tenants.ts +0 -101
  183. package/src/platform/tests/tenants.spec.ts +0 -26
  184. package/src/platform/users.ts +0 -129
  185. package/src/plugin/index.ts +0 -1
  186. package/src/plugin/tests/validation.spec.ts +0 -209
  187. package/src/plugin/utils.ts +0 -175
  188. package/src/queue/constants.ts +0 -8
  189. package/src/queue/inMemoryQueue.ts +0 -189
  190. package/src/queue/index.ts +0 -2
  191. package/src/queue/listeners.ts +0 -199
  192. package/src/queue/queue.ts +0 -84
  193. package/src/redis/index.ts +0 -6
  194. package/src/redis/init.ts +0 -118
  195. package/src/redis/redis.ts +0 -358
  196. package/src/redis/redlockImpl.ts +0 -155
  197. package/src/redis/tests/redis.spec.ts +0 -207
  198. package/src/redis/tests/redlockImpl.spec.ts +0 -105
  199. package/src/redis/utils.ts +0 -128
  200. package/src/security/auth.ts +0 -24
  201. package/src/security/encryption.ts +0 -185
  202. package/src/security/index.ts +0 -1
  203. package/src/security/permissions.ts +0 -166
  204. package/src/security/roles.ts +0 -655
  205. package/src/security/secrets.ts +0 -20
  206. package/src/security/sessions.ts +0 -123
  207. package/src/security/tests/auth.spec.ts +0 -45
  208. package/src/security/tests/encryption.spec.ts +0 -31
  209. package/src/security/tests/permissions.spec.ts +0 -146
  210. package/src/security/tests/secrets.spec.ts +0 -35
  211. package/src/security/tests/sessions.spec.ts +0 -12
  212. package/src/sql/designDoc.ts +0 -17
  213. package/src/sql/index.ts +0 -5
  214. package/src/sql/sql.ts +0 -1854
  215. package/src/sql/sqlTable.ts +0 -319
  216. package/src/sql/utils.ts +0 -193
  217. package/src/tenancy/db.ts +0 -6
  218. package/src/tenancy/index.ts +0 -2
  219. package/src/tenancy/tenancy.ts +0 -148
  220. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  221. package/src/timers/index.ts +0 -1
  222. package/src/timers/timers.ts +0 -22
  223. package/src/users/db.ts +0 -582
  224. package/src/users/events.ts +0 -176
  225. package/src/users/index.ts +0 -4
  226. package/src/users/lookup.ts +0 -99
  227. package/src/users/test/db.spec.ts +0 -188
  228. package/src/users/test/utils.spec.ts +0 -67
  229. package/src/users/users.ts +0 -353
  230. package/src/users/utils.ts +0 -81
  231. package/src/utils/Duration.ts +0 -56
  232. package/src/utils/hashing.ts +0 -15
  233. package/src/utils/index.ts +0 -4
  234. package/src/utils/stringUtils.ts +0 -8
  235. package/src/utils/tests/Duration.spec.ts +0 -19
  236. package/src/utils/tests/utils.spec.ts +0 -204
  237. package/src/utils/utils.ts +0 -249
  238. package/tests/core/logging.ts +0 -34
  239. package/tests/core/users/users.spec.js +0 -53
  240. package/tests/core/utilities/index.ts +0 -7
  241. package/tests/core/utilities/jestUtils.ts +0 -33
  242. package/tests/core/utilities/mocks/alerts.ts +0 -4
  243. package/tests/core/utilities/mocks/date.ts +0 -3
  244. package/tests/core/utilities/mocks/events.ts +0 -132
  245. package/tests/core/utilities/mocks/index.ts +0 -9
  246. package/tests/core/utilities/mocks/licenses.ts +0 -119
  247. package/tests/core/utilities/queue.ts +0 -9
  248. package/tests/core/utilities/structures/Chance.ts +0 -20
  249. package/tests/core/utilities/structures/accounts.ts +0 -80
  250. package/tests/core/utilities/structures/apps.ts +0 -21
  251. package/tests/core/utilities/structures/common.ts +0 -7
  252. package/tests/core/utilities/structures/db.ts +0 -12
  253. package/tests/core/utilities/structures/documents/index.ts +0 -1
  254. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  255. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  256. package/tests/core/utilities/structures/generator.ts +0 -3
  257. package/tests/core/utilities/structures/index.ts +0 -15
  258. package/tests/core/utilities/structures/koa.ts +0 -16
  259. package/tests/core/utilities/structures/licenses.ts +0 -190
  260. package/tests/core/utilities/structures/plugins.ts +0 -19
  261. package/tests/core/utilities/structures/quotas.ts +0 -72
  262. package/tests/core/utilities/structures/scim.ts +0 -80
  263. package/tests/core/utilities/structures/sso.ts +0 -118
  264. package/tests/core/utilities/structures/tenants.ts +0 -5
  265. package/tests/core/utilities/structures/userGroups.ts +0 -10
  266. package/tests/core/utilities/structures/users.ts +0 -89
  267. package/tests/core/utilities/testContainerUtils.ts +0 -165
  268. package/tests/core/utilities/utils/index.ts +0 -2
  269. package/tests/core/utilities/utils/queue.ts +0 -27
  270. package/tests/core/utilities/utils/time.ts +0 -3
  271. package/tests/extra/DBTestConfiguration.ts +0 -36
  272. package/tests/extra/index.ts +0 -2
  273. package/tests/extra/testEnv.ts +0 -95
  274. package/tests/index.ts +0 -2
  275. package/tests/jestEnv.ts +0 -10
  276. package/tests/jestSetup.ts +0 -36
@@ -1,152 +0,0 @@
1
- import fetch from "node-fetch"
2
- import * as sso from "./sso"
3
- import { ssoCallbackUrl } from "../utils"
4
- import { validEmail } from "../../../utils"
5
- import {
6
- ConfigType,
7
- OIDCInnerConfig,
8
- SSOProfile,
9
- OIDCStrategyConfiguration,
10
- SSOAuthDetails,
11
- SSOProviderType,
12
- JwtClaims,
13
- SaveSSOUserFunction,
14
- } from "@budibase/types"
15
-
16
- const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy
17
-
18
- export function buildVerifyFn(saveUserFn: SaveSSOUserFunction) {
19
- /**
20
- * @param issuer The identity provider base URL
21
- * @param sub The user ID
22
- * @param profile The user profile information. Created by passport from the /userinfo response
23
- * @param jwtClaims The parsed id_token claims
24
- * @param accessToken The access_token for contacting the identity provider - may or may not be a JWT
25
- * @param refreshToken The refresh_token for obtaining a new access_token - usually not a JWT
26
- * @param idToken The id_token - always a JWT
27
- * @param params The response body from requesting an access_token
28
- * @param done The passport callback: err, user, info
29
- */
30
- return async (
31
- issuer: string,
32
- sub: string,
33
- profile: SSOProfile,
34
- jwtClaims: JwtClaims,
35
- accessToken: string,
36
- refreshToken: string,
37
- idToken: string,
38
- params: any,
39
- done: Function
40
- ) => {
41
- const details: SSOAuthDetails = {
42
- // store the issuer info to enable sync in future
43
- provider: issuer,
44
- providerType: SSOProviderType.OIDC,
45
- userId: profile.id,
46
- profile: profile,
47
- email: getEmail(profile, jwtClaims),
48
- oauth2: {
49
- accessToken: accessToken,
50
- refreshToken: refreshToken,
51
- },
52
- }
53
-
54
- return sso.authenticate(
55
- details,
56
- false, // don't require local accounts to exist
57
- done,
58
- saveUserFn
59
- )
60
- }
61
- }
62
-
63
- /**
64
- * @param profile The structured profile created by passport using the user info endpoint
65
- * @param jwtClaims The claims returned in the id token
66
- */
67
- function getEmail(profile: SSOProfile, jwtClaims: JwtClaims) {
68
- // profile not guaranteed to contain email e.g. github connected azure ad account
69
- if (profile._json.email) {
70
- return profile._json.email
71
- }
72
-
73
- // fallback to id token email
74
- if (jwtClaims.email) {
75
- return jwtClaims.email
76
- }
77
-
78
- // fallback to id token preferred username
79
- const username = jwtClaims.preferred_username
80
- if (username && validEmail(username)) {
81
- return username
82
- }
83
-
84
- throw new Error(
85
- `Could not determine user email from profile ${JSON.stringify(
86
- profile
87
- )} and claims ${JSON.stringify(jwtClaims)}`
88
- )
89
- }
90
-
91
- /**
92
- * Create an instance of the oidc passport strategy. This wrapper fetches the configuration
93
- * from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
94
- * @returns Dynamically configured Passport OIDC Strategy
95
- */
96
- export async function strategyFactory(
97
- config: OIDCStrategyConfiguration,
98
- saveUserFn: SaveSSOUserFunction
99
- ) {
100
- try {
101
- const verify = buildVerifyFn(saveUserFn)
102
- const strategy = new OIDCStrategy(config, verify)
103
- strategy.name = "oidc"
104
- return strategy
105
- } catch (err: any) {
106
- throw new Error(`Error constructing OIDC authentication strategy - ${err}`)
107
- }
108
- }
109
-
110
- export async function fetchStrategyConfig(
111
- oidcConfig: OIDCInnerConfig,
112
- callbackUrl?: string
113
- ): Promise<OIDCStrategyConfiguration> {
114
- try {
115
- const { clientID, clientSecret, configUrl } = oidcConfig
116
-
117
- if (!clientID || !clientSecret || !callbackUrl || !configUrl) {
118
- // check for remote config and all required elements
119
- throw new Error(
120
- "Configuration invalid. Must contain clientID, clientSecret, callbackUrl and configUrl"
121
- )
122
- }
123
-
124
- const response = await fetch(configUrl)
125
-
126
- if (!response.ok) {
127
- throw new Error(
128
- `Unexpected response when fetching openid-configuration: ${response.statusText}`
129
- )
130
- }
131
-
132
- const body = await response.json()
133
-
134
- return {
135
- issuer: body.issuer,
136
- authorizationURL: body.authorization_endpoint,
137
- tokenURL: body.token_endpoint,
138
- userInfoURL: body.userinfo_endpoint,
139
- clientID: clientID,
140
- clientSecret: clientSecret,
141
- callbackURL: callbackUrl,
142
- }
143
- } catch (err) {
144
- throw new Error(
145
- `Error constructing OIDC authentication configuration - ${err}`
146
- )
147
- }
148
- }
149
-
150
- export async function getCallbackUrl() {
151
- return ssoCallbackUrl(ConfigType.OIDC)
152
- }
@@ -1,138 +0,0 @@
1
- import { generateGlobalUserID } from "../../../db"
2
- import { authError } from "../utils"
3
- import * as users from "../../../users"
4
- import * as context from "../../../context"
5
- import {
6
- SaveSSOUserFunction,
7
- SSOAuthDetails,
8
- SSOUser,
9
- User,
10
- } from "@budibase/types"
11
-
12
- // no-op function for user save
13
- // - this allows datasource auth and access token refresh to work correctly
14
- // - prefer no-op over an optional argument to ensure function is provided to login flows
15
- export const ssoSaveUserNoOp: SaveSSOUserFunction = (user: SSOUser) =>
16
- Promise.resolve(user)
17
-
18
- /**
19
- * Common authentication logic for third parties. e.g. OAuth, OIDC.
20
- */
21
- export async function authenticate(
22
- details: SSOAuthDetails,
23
- requireLocalAccount: boolean = true,
24
- done: any,
25
- saveUserFn: SaveSSOUserFunction
26
- ) {
27
- if (!saveUserFn) {
28
- throw new Error("Save user function must be provided")
29
- }
30
- if (!details.userId) {
31
- return authError(done, "sso user id required")
32
- }
33
- if (!details.email) {
34
- return authError(done, "sso user email required")
35
- }
36
-
37
- // use the third party id
38
- const userId = generateGlobalUserID(details.userId)
39
-
40
- let dbUser: User | undefined
41
-
42
- // try to load by id
43
- try {
44
- dbUser = await users.getById(userId)
45
- } catch (err: any) {
46
- // abort when not 404 error
47
- if (!err.status || err.status !== 404) {
48
- return authError(
49
- done,
50
- "Unexpected error when retrieving existing user",
51
- err
52
- )
53
- }
54
- }
55
-
56
- // fallback to loading by email
57
- if (!dbUser) {
58
- dbUser = await users.getGlobalUserByEmail(details.email)
59
- }
60
-
61
- // exit early if there is still no user and auto creation is disabled
62
- if (!dbUser && requireLocalAccount) {
63
- return authError(
64
- done,
65
- "Email does not yet exist. You must set up your local budibase account first."
66
- )
67
- }
68
-
69
- // first time creation
70
- if (!dbUser) {
71
- // setup a blank user using the third party id
72
- dbUser = {
73
- _id: userId,
74
- email: details.email,
75
- roles: {},
76
- tenantId: context.getTenantId(),
77
- }
78
- }
79
-
80
- let ssoUser = await syncUser(dbUser, details)
81
- // never prompt for password reset
82
- ssoUser.forceResetPassword = false
83
-
84
- try {
85
- // don't try to re-save any existing password
86
- delete ssoUser.password
87
- // create or sync the user
88
- ssoUser = (await saveUserFn(ssoUser, {
89
- hashPassword: false,
90
- requirePassword: false,
91
- })) as SSOUser
92
- } catch (err: any) {
93
- return authError(done, "Error saving user", err)
94
- }
95
-
96
- return done(null, ssoUser)
97
- }
98
-
99
- /**
100
- * @returns a user that has been sync'd with third party information
101
- */
102
- async function syncUser(user: User, details: SSOAuthDetails): Promise<SSOUser> {
103
- let firstName
104
- let lastName
105
- let oauth2
106
-
107
- if (details.profile) {
108
- const profile = details.profile
109
-
110
- if (profile.name) {
111
- const name = profile.name
112
- // first name
113
- if (name.givenName) {
114
- firstName = name.givenName
115
- }
116
- // last name
117
- if (name.familyName) {
118
- lastName = name.familyName
119
- }
120
- }
121
- }
122
-
123
- // oauth tokens for future use
124
- if (details.oauth2) {
125
- oauth2 = {
126
- ...details.oauth2,
127
- }
128
- }
129
-
130
- return {
131
- ...user,
132
- provider: details.provider,
133
- providerType: details.providerType,
134
- firstName,
135
- lastName,
136
- oauth2,
137
- }
138
- }
@@ -1,68 +0,0 @@
1
- import { generator, structures } from "../../../../../tests"
2
- import { SSOProviderType } from "@budibase/types"
3
-
4
- jest.mock("passport-google-oauth")
5
- const mockStrategy = require("passport-google-oauth").OAuth2Strategy
6
-
7
- jest.mock("../sso")
8
- import * as _sso from "../sso"
9
-
10
- const sso = jest.mocked(_sso)
11
-
12
- const mockSaveUserFn = jest.fn()
13
- const mockDone = jest.fn()
14
-
15
- import * as google from "../google"
16
-
17
- describe("google", () => {
18
- describe("strategyFactory", () => {
19
- const googleConfig = structures.sso.googleConfig()
20
- const callbackUrl = generator.url()
21
-
22
- it("should create successfully create a google strategy", async () => {
23
- await google.strategyFactory(googleConfig, callbackUrl, mockSaveUserFn)
24
-
25
- const expectedOptions = {
26
- clientID: googleConfig.clientID,
27
- clientSecret: googleConfig.clientSecret,
28
- callbackURL: callbackUrl,
29
- }
30
-
31
- expect(mockStrategy).toHaveBeenCalledWith(
32
- expectedOptions,
33
- expect.anything()
34
- )
35
- })
36
- })
37
-
38
- describe("authenticate", () => {
39
- const details = structures.sso.authDetails()
40
- details.provider = "google"
41
- details.providerType = SSOProviderType.GOOGLE
42
-
43
- const profile = details.profile!
44
- profile.provider = "google"
45
-
46
- beforeEach(() => {
47
- jest.clearAllMocks()
48
- })
49
-
50
- it("delegates authentication to third party common", async () => {
51
- const authenticate = await google.buildVerifyFn(mockSaveUserFn)
52
-
53
- await authenticate(
54
- details.oauth2.accessToken,
55
- details.oauth2.refreshToken!,
56
- profile,
57
- mockDone
58
- )
59
-
60
- expect(sso.authenticate).toHaveBeenCalledWith(
61
- details,
62
- true,
63
- mockDone,
64
- mockSaveUserFn
65
- )
66
- })
67
- })
68
- })
@@ -1,144 +0,0 @@
1
- import { generator, structures } from "../../../../../tests"
2
- import {
3
- JwtClaims,
4
- OIDCInnerConfig,
5
- SSOAuthDetails,
6
- SSOProviderType,
7
- } from "@budibase/types"
8
- import * as _sso from "../sso"
9
- import * as oidc from "../oidc"
10
- import nock from "nock"
11
-
12
- jest.mock("@techpass/passport-openidconnect")
13
- const mockStrategy = require("@techpass/passport-openidconnect").Strategy
14
-
15
- jest.mock("../sso")
16
- const sso = jest.mocked(_sso)
17
-
18
- const mockSaveUser = jest.fn()
19
- const mockDone = jest.fn()
20
-
21
- describe("oidc", () => {
22
- const callbackUrl = generator.url()
23
- const oidcConfig: OIDCInnerConfig = structures.sso.oidcConfig()
24
- const wellKnownConfig = structures.sso.oidcWellKnownConfig()
25
-
26
- beforeEach(() => {
27
- nock.cleanAll()
28
- nock(oidcConfig.configUrl).get("/").reply(200, wellKnownConfig)
29
- })
30
-
31
- describe("strategyFactory", () => {
32
- it("should create successfully create an oidc strategy", async () => {
33
- const strategyConfiguration = await oidc.fetchStrategyConfig(
34
- oidcConfig,
35
- callbackUrl
36
- )
37
- await oidc.strategyFactory(strategyConfiguration, mockSaveUser)
38
-
39
- const expectedOptions = {
40
- issuer: wellKnownConfig.issuer,
41
- authorizationURL: wellKnownConfig.authorization_endpoint,
42
- tokenURL: wellKnownConfig.token_endpoint,
43
- userInfoURL: wellKnownConfig.userinfo_endpoint,
44
- clientID: oidcConfig.clientID,
45
- clientSecret: oidcConfig.clientSecret,
46
- callbackURL: callbackUrl,
47
- }
48
- expect(mockStrategy).toHaveBeenCalledWith(
49
- expectedOptions,
50
- expect.anything()
51
- )
52
- })
53
- })
54
-
55
- describe("authenticate", () => {
56
- const details: SSOAuthDetails = structures.sso.authDetails()
57
- details.providerType = SSOProviderType.OIDC
58
- const profile = details.profile!
59
- const issuer = profile.provider
60
-
61
- const sub = generator.string()
62
- const idToken = generator.string()
63
- const params = {}
64
-
65
- let authenticateFn: any
66
- let jwtClaims: JwtClaims
67
-
68
- beforeEach(async () => {
69
- jest.clearAllMocks()
70
- authenticateFn = await oidc.buildVerifyFn(mockSaveUser)
71
- })
72
-
73
- async function authenticate() {
74
- await authenticateFn(
75
- issuer,
76
- sub,
77
- profile,
78
- jwtClaims,
79
- details.oauth2.accessToken,
80
- details.oauth2.refreshToken,
81
- idToken,
82
- params,
83
- mockDone
84
- )
85
- }
86
-
87
- it("passes auth details to sso module", async () => {
88
- await authenticate()
89
-
90
- expect(sso.authenticate).toHaveBeenCalledWith(
91
- details,
92
- false,
93
- mockDone,
94
- mockSaveUser
95
- )
96
- })
97
-
98
- it("uses JWT email to get email", async () => {
99
- delete profile._json.email
100
-
101
- jwtClaims = {
102
- email: details.email,
103
- }
104
-
105
- await authenticate()
106
-
107
- expect(sso.authenticate).toHaveBeenCalledWith(
108
- details,
109
- false,
110
- mockDone,
111
- mockSaveUser
112
- )
113
- })
114
-
115
- it("uses JWT username to get email", async () => {
116
- delete profile._json.email
117
-
118
- jwtClaims = {
119
- email: details.email,
120
- }
121
-
122
- await authenticate()
123
-
124
- expect(sso.authenticate).toHaveBeenCalledWith(
125
- details,
126
- false,
127
- mockDone,
128
- mockSaveUser
129
- )
130
- })
131
-
132
- it("uses JWT invalid username to get email", async () => {
133
- delete profile._json.email
134
-
135
- jwtClaims = {
136
- preferred_username: "invalidUsername",
137
- }
138
-
139
- await expect(authenticate()).rejects.toThrow(
140
- "Could not determine user email from profile"
141
- )
142
- })
143
- })
144
- })
@@ -1,197 +0,0 @@
1
- import { structures } from "../../../../../tests"
2
- import { testEnv } from "../../../../../tests/extra"
3
- import { SSOAuthDetails, User } from "@budibase/types"
4
-
5
- import { HTTPError } from "../../../../errors"
6
- import * as sso from "../sso"
7
- import * as context from "../../../../context"
8
- import nock from "nock"
9
-
10
- const mockDone = jest.fn()
11
- const mockSaveUser = jest.fn()
12
-
13
- jest.mock("../../../../users")
14
- import * as _users from "../../../../users"
15
-
16
- const users = jest.mocked(_users)
17
-
18
- const getErrorMessage = () => {
19
- return mockDone.mock.calls[0][2].message
20
- }
21
-
22
- describe("sso", () => {
23
- describe("authenticate", () => {
24
- beforeEach(() => {
25
- jest.clearAllMocks()
26
- testEnv.singleTenant()
27
- nock.cleanAll()
28
- })
29
-
30
- describe("validation", () => {
31
- const testValidation = async (
32
- details: SSOAuthDetails,
33
- message: string
34
- ) => {
35
- await sso.authenticate(details, false, mockDone, mockSaveUser)
36
-
37
- expect(mockDone.mock.calls.length).toBe(1)
38
- expect(getErrorMessage()).toContain(message)
39
- }
40
-
41
- it("user id fails", async () => {
42
- const details = structures.sso.authDetails()
43
- details.userId = undefined!
44
-
45
- await testValidation(details, "sso user id required")
46
- })
47
-
48
- it("email fails", async () => {
49
- const details = structures.sso.authDetails()
50
- details.email = undefined!
51
-
52
- await testValidation(details, "sso user email required")
53
- })
54
- })
55
-
56
- describe("when the user doesn't exist", () => {
57
- let user: User
58
- let details: SSOAuthDetails
59
-
60
- beforeEach(() => {
61
- users.getById.mockImplementationOnce(() => {
62
- throw new HTTPError("", 404)
63
- })
64
-
65
- nock("http://example.com").get("/").reply(200, undefined, {
66
- "Content-Type": "image/png",
67
- })
68
-
69
- user = structures.users.user()
70
- delete user._rev
71
- delete user._id
72
-
73
- details = structures.sso.authDetails(user)
74
- details.userId = structures.uuid()
75
- })
76
-
77
- describe("when a local account is required", () => {
78
- it("returns an error message", async () => {
79
- const details = structures.sso.authDetails()
80
-
81
- await sso.authenticate(details, true, mockDone, mockSaveUser)
82
-
83
- expect(mockDone.mock.calls.length).toBe(1)
84
- expect(getErrorMessage()).toContain(
85
- "Email does not yet exist. You must set up your local budibase account first."
86
- )
87
- })
88
- })
89
-
90
- describe("when a local account isn't required", () => {
91
- it("creates and authenticates the user", async () => {
92
- const ssoUser = structures.users.ssoUser({ user, details })
93
- mockSaveUser.mockReturnValueOnce(ssoUser)
94
-
95
- await sso.authenticate(details, false, mockDone, mockSaveUser)
96
-
97
- // default roles for new user
98
- ssoUser.roles = {}
99
-
100
- // modified external id to match user format
101
- ssoUser._id = "us_" + details.userId
102
- delete ssoUser.userId
103
-
104
- // new sso user won't have a password
105
- delete ssoUser.password
106
-
107
- // new user isn't saved with rev
108
- delete ssoUser._rev
109
-
110
- // tenant id added
111
- ssoUser.tenantId = context.getTenantId()
112
-
113
- expect(mockSaveUser).toHaveBeenCalledWith(ssoUser, {
114
- hashPassword: false,
115
- requirePassword: false,
116
- })
117
- expect(mockDone).toHaveBeenCalledWith(null, ssoUser)
118
- })
119
- })
120
- })
121
-
122
- describe("when the user exists", () => {
123
- let existingUser: User
124
- let details: SSOAuthDetails
125
-
126
- beforeEach(() => {
127
- existingUser = structures.users.user()
128
- existingUser._id = structures.uuid()
129
- details = structures.sso.authDetails(existingUser)
130
- nock("http://example.com").get("/").reply(200, undefined, {
131
- "Content-Type": "image/png",
132
- })
133
- })
134
-
135
- describe("exists by email", () => {
136
- beforeEach(() => {
137
- users.getById.mockImplementationOnce(() => {
138
- throw new HTTPError("", 404)
139
- })
140
- users.getGlobalUserByEmail.mockReturnValueOnce(
141
- Promise.resolve(existingUser)
142
- )
143
- })
144
-
145
- it("syncs and authenticates the user", async () => {
146
- const ssoUser = structures.users.ssoUser({
147
- user: existingUser,
148
- details,
149
- })
150
- mockSaveUser.mockReturnValueOnce(ssoUser)
151
-
152
- await sso.authenticate(details, true, mockDone, mockSaveUser)
153
-
154
- // roles preserved
155
- ssoUser.roles = existingUser.roles
156
-
157
- // existing id preserved
158
- ssoUser._id = existingUser._id
159
-
160
- expect(mockSaveUser).toHaveBeenCalledWith(ssoUser, {
161
- hashPassword: false,
162
- requirePassword: false,
163
- })
164
- expect(mockDone).toHaveBeenCalledWith(null, ssoUser)
165
- })
166
- })
167
-
168
- describe("exists by id", () => {
169
- beforeEach(() => {
170
- users.getById.mockReturnValueOnce(Promise.resolve(existingUser))
171
- })
172
-
173
- it("syncs and authenticates the user", async () => {
174
- const ssoUser = structures.users.ssoUser({
175
- user: existingUser,
176
- details,
177
- })
178
- mockSaveUser.mockReturnValueOnce(ssoUser)
179
-
180
- await sso.authenticate(details, true, mockDone, mockSaveUser)
181
-
182
- // roles preserved
183
- ssoUser.roles = existingUser.roles
184
-
185
- // existing id preserved
186
- ssoUser._id = existingUser._id
187
-
188
- expect(mockSaveUser).toHaveBeenCalledWith(ssoUser, {
189
- hashPassword: false,
190
- requirePassword: false,
191
- })
192
- expect(mockDone).toHaveBeenCalledWith(null, ssoUser)
193
- })
194
- })
195
- })
196
- })
197
- })