@budibase/backend-core 3.2.4 → 3.2.6

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 (272) hide show
  1. package/dist/index.js.map +1 -1
  2. package/dist/index.js.meta.json +1 -1
  3. package/dist/package.json +11 -4
  4. package/dist/plugins.js.meta.json +1 -1
  5. package/package.json +11 -4
  6. package/src/accounts/accounts.ts +0 -82
  7. package/src/accounts/api.ts +0 -59
  8. package/src/accounts/index.ts +0 -1
  9. package/src/auth/auth.ts +0 -210
  10. package/src/auth/index.ts +0 -1
  11. package/src/auth/tests/auth.spec.ts +0 -14
  12. package/src/blacklist/blacklist.ts +0 -54
  13. package/src/blacklist/index.ts +0 -1
  14. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  15. package/src/cache/appMetadata.ts +0 -88
  16. package/src/cache/base/index.ts +0 -150
  17. package/src/cache/docWritethrough.ts +0 -105
  18. package/src/cache/generic.ts +0 -33
  19. package/src/cache/index.ts +0 -8
  20. package/src/cache/invite.ts +0 -86
  21. package/src/cache/passwordReset.ts +0 -49
  22. package/src/cache/tests/docWritethrough.spec.ts +0 -296
  23. package/src/cache/tests/user.spec.ts +0 -145
  24. package/src/cache/tests/writethrough.spec.ts +0 -139
  25. package/src/cache/user.ts +0 -154
  26. package/src/cache/writethrough.ts +0 -133
  27. package/src/configs/configs.ts +0 -263
  28. package/src/configs/index.ts +0 -1
  29. package/src/configs/tests/configs.spec.ts +0 -184
  30. package/src/constants/db.ts +0 -75
  31. package/src/constants/index.ts +0 -2
  32. package/src/constants/misc.ts +0 -36
  33. package/src/context/Context.ts +0 -14
  34. package/src/context/identity.ts +0 -58
  35. package/src/context/index.ts +0 -3
  36. package/src/context/mainContext.ts +0 -422
  37. package/src/context/tests/index.spec.ts +0 -255
  38. package/src/context/types.ts +0 -26
  39. package/src/db/Replication.ts +0 -94
  40. package/src/db/couch/DatabaseImpl.ts +0 -511
  41. package/src/db/couch/connections.ts +0 -89
  42. package/src/db/couch/index.ts +0 -4
  43. package/src/db/couch/pouchDB.ts +0 -97
  44. package/src/db/couch/pouchDump.ts +0 -0
  45. package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
  46. package/src/db/couch/utils.ts +0 -55
  47. package/src/db/db.ts +0 -34
  48. package/src/db/errors.ts +0 -14
  49. package/src/db/index.ts +0 -12
  50. package/src/db/instrumentation.ts +0 -199
  51. package/src/db/lucene.ts +0 -721
  52. package/src/db/searchIndexes/index.ts +0 -1
  53. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  54. package/src/db/tests/DatabaseImpl.spec.ts +0 -55
  55. package/src/db/tests/connections.spec.ts +0 -22
  56. package/src/db/tests/index.spec.ts +0 -32
  57. package/src/db/tests/lucene.spec.ts +0 -400
  58. package/src/db/tests/pouch.spec.js +0 -62
  59. package/src/db/tests/utils.spec.ts +0 -63
  60. package/src/db/utils.ts +0 -208
  61. package/src/db/views.ts +0 -245
  62. package/src/docIds/conversions.ts +0 -60
  63. package/src/docIds/ids.ts +0 -126
  64. package/src/docIds/index.ts +0 -2
  65. package/src/docIds/newid.ts +0 -5
  66. package/src/docIds/params.ts +0 -189
  67. package/src/docUpdates/index.ts +0 -24
  68. package/src/environment.ts +0 -293
  69. package/src/errors/errors.ts +0 -119
  70. package/src/errors/index.ts +0 -1
  71. package/src/events/analytics.ts +0 -6
  72. package/src/events/asyncEvents/index.ts +0 -2
  73. package/src/events/asyncEvents/publisher.ts +0 -12
  74. package/src/events/asyncEvents/queue.ts +0 -22
  75. package/src/events/backfill.ts +0 -183
  76. package/src/events/documentId.ts +0 -56
  77. package/src/events/events.ts +0 -47
  78. package/src/events/identification.ts +0 -311
  79. package/src/events/index.ts +0 -15
  80. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  81. package/src/events/processors/AuditLogsProcessor.ts +0 -92
  82. package/src/events/processors/LoggingProcessor.ts +0 -36
  83. package/src/events/processors/Processors.ts +0 -52
  84. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
  85. package/src/events/processors/index.ts +0 -19
  86. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  87. package/src/events/processors/posthog/index.ts +0 -3
  88. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  89. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
  90. package/src/events/processors/types.ts +0 -1
  91. package/src/events/publishers/account.ts +0 -41
  92. package/src/events/publishers/ai.ts +0 -21
  93. package/src/events/publishers/app.ts +0 -168
  94. package/src/events/publishers/auditLog.ts +0 -26
  95. package/src/events/publishers/auth.ts +0 -73
  96. package/src/events/publishers/automation.ts +0 -110
  97. package/src/events/publishers/backfill.ts +0 -74
  98. package/src/events/publishers/backup.ts +0 -42
  99. package/src/events/publishers/datasource.ts +0 -48
  100. package/src/events/publishers/email.ts +0 -17
  101. package/src/events/publishers/environmentVariable.ts +0 -38
  102. package/src/events/publishers/group.ts +0 -99
  103. package/src/events/publishers/index.ts +0 -25
  104. package/src/events/publishers/installation.ts +0 -38
  105. package/src/events/publishers/layout.ts +0 -26
  106. package/src/events/publishers/license.ts +0 -84
  107. package/src/events/publishers/org.ts +0 -37
  108. package/src/events/publishers/plugin.ts +0 -47
  109. package/src/events/publishers/query.ts +0 -89
  110. package/src/events/publishers/role.ts +0 -62
  111. package/src/events/publishers/rows.ts +0 -29
  112. package/src/events/publishers/screen.ts +0 -36
  113. package/src/events/publishers/serve.ts +0 -43
  114. package/src/events/publishers/table.ts +0 -70
  115. package/src/events/publishers/user.ts +0 -202
  116. package/src/events/publishers/view.ts +0 -107
  117. package/src/features/features.ts +0 -277
  118. package/src/features/index.ts +0 -2
  119. package/src/features/tests/features.spec.ts +0 -267
  120. package/src/features/tests/utils.ts +0 -64
  121. package/src/helpers.ts +0 -9
  122. package/src/index.ts +0 -59
  123. package/src/installation.ts +0 -115
  124. package/src/logging/alerts.ts +0 -26
  125. package/src/logging/correlation/correlation.ts +0 -15
  126. package/src/logging/correlation/index.ts +0 -1
  127. package/src/logging/correlation/middleware.ts +0 -18
  128. package/src/logging/index.ts +0 -4
  129. package/src/logging/pino/logger.ts +0 -239
  130. package/src/logging/pino/middleware.ts +0 -48
  131. package/src/logging/system.ts +0 -81
  132. package/src/logging/tests/system.spec.ts +0 -61
  133. package/src/middleware/adminOnly.ts +0 -9
  134. package/src/middleware/auditLog.ts +0 -6
  135. package/src/middleware/authenticated.ts +0 -247
  136. package/src/middleware/builderOnly.ts +0 -21
  137. package/src/middleware/builderOrAdmin.ts +0 -21
  138. package/src/middleware/contentSecurityPolicy.ts +0 -113
  139. package/src/middleware/csrf.ts +0 -81
  140. package/src/middleware/errorHandling.ts +0 -43
  141. package/src/middleware/index.ts +0 -24
  142. package/src/middleware/internalApi.ts +0 -23
  143. package/src/middleware/ip.ts +0 -12
  144. package/src/middleware/joi-validator.ts +0 -58
  145. package/src/middleware/matchers.ts +0 -39
  146. package/src/middleware/passport/datasource/google.ts +0 -102
  147. package/src/middleware/passport/local.ts +0 -54
  148. package/src/middleware/passport/sso/google.ts +0 -77
  149. package/src/middleware/passport/sso/oidc.ts +0 -152
  150. package/src/middleware/passport/sso/sso.ts +0 -138
  151. package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
  152. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
  153. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  154. package/src/middleware/passport/utils.ts +0 -38
  155. package/src/middleware/querystringToBody.ts +0 -28
  156. package/src/middleware/tenancy.ts +0 -36
  157. package/src/middleware/tests/builder.spec.ts +0 -181
  158. package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
  159. package/src/middleware/tests/matchers.spec.ts +0 -100
  160. package/src/migrations/definitions.ts +0 -40
  161. package/src/migrations/index.ts +0 -2
  162. package/src/migrations/migrations.ts +0 -186
  163. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  164. package/src/migrations/tests/migrations.spec.ts +0 -64
  165. package/src/objectStore/buckets/app.ts +0 -53
  166. package/src/objectStore/buckets/global.ts +0 -29
  167. package/src/objectStore/buckets/index.ts +0 -3
  168. package/src/objectStore/buckets/plugins.ts +0 -71
  169. package/src/objectStore/buckets/tests/app.spec.ts +0 -161
  170. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  171. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  172. package/src/objectStore/cloudfront.ts +0 -41
  173. package/src/objectStore/index.ts +0 -3
  174. package/src/objectStore/objectStore.ts +0 -585
  175. package/src/objectStore/utils.ts +0 -113
  176. package/src/platform/index.ts +0 -3
  177. package/src/platform/platformDb.ts +0 -6
  178. package/src/platform/tenants.ts +0 -101
  179. package/src/platform/tests/tenants.spec.ts +0 -26
  180. package/src/platform/users.ts +0 -129
  181. package/src/plugin/index.ts +0 -1
  182. package/src/plugin/tests/validation.spec.ts +0 -209
  183. package/src/plugin/utils.ts +0 -175
  184. package/src/queue/constants.ts +0 -8
  185. package/src/queue/inMemoryQueue.ts +0 -189
  186. package/src/queue/index.ts +0 -2
  187. package/src/queue/listeners.ts +0 -199
  188. package/src/queue/queue.ts +0 -84
  189. package/src/redis/index.ts +0 -6
  190. package/src/redis/init.ts +0 -118
  191. package/src/redis/redis.ts +0 -358
  192. package/src/redis/redlockImpl.ts +0 -155
  193. package/src/redis/tests/redis.spec.ts +0 -207
  194. package/src/redis/tests/redlockImpl.spec.ts +0 -105
  195. package/src/redis/utils.ts +0 -128
  196. package/src/security/auth.ts +0 -24
  197. package/src/security/encryption.ts +0 -185
  198. package/src/security/index.ts +0 -1
  199. package/src/security/permissions.ts +0 -166
  200. package/src/security/roles.ts +0 -655
  201. package/src/security/secrets.ts +0 -20
  202. package/src/security/sessions.ts +0 -123
  203. package/src/security/tests/auth.spec.ts +0 -45
  204. package/src/security/tests/encryption.spec.ts +0 -31
  205. package/src/security/tests/permissions.spec.ts +0 -146
  206. package/src/security/tests/secrets.spec.ts +0 -35
  207. package/src/security/tests/sessions.spec.ts +0 -12
  208. package/src/sql/designDoc.ts +0 -17
  209. package/src/sql/index.ts +0 -5
  210. package/src/sql/sql.ts +0 -1854
  211. package/src/sql/sqlTable.ts +0 -319
  212. package/src/sql/utils.ts +0 -193
  213. package/src/tenancy/db.ts +0 -6
  214. package/src/tenancy/index.ts +0 -2
  215. package/src/tenancy/tenancy.ts +0 -148
  216. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  217. package/src/timers/index.ts +0 -1
  218. package/src/timers/timers.ts +0 -22
  219. package/src/users/db.ts +0 -582
  220. package/src/users/events.ts +0 -176
  221. package/src/users/index.ts +0 -4
  222. package/src/users/lookup.ts +0 -99
  223. package/src/users/test/db.spec.ts +0 -188
  224. package/src/users/test/utils.spec.ts +0 -67
  225. package/src/users/users.ts +0 -353
  226. package/src/users/utils.ts +0 -81
  227. package/src/utils/Duration.ts +0 -56
  228. package/src/utils/hashing.ts +0 -15
  229. package/src/utils/index.ts +0 -4
  230. package/src/utils/stringUtils.ts +0 -8
  231. package/src/utils/tests/Duration.spec.ts +0 -19
  232. package/src/utils/tests/utils.spec.ts +0 -204
  233. package/src/utils/utils.ts +0 -249
  234. package/tests/core/logging.ts +0 -34
  235. package/tests/core/users/users.spec.js +0 -53
  236. package/tests/core/utilities/index.ts +0 -7
  237. package/tests/core/utilities/jestUtils.ts +0 -33
  238. package/tests/core/utilities/mocks/alerts.ts +0 -4
  239. package/tests/core/utilities/mocks/date.ts +0 -3
  240. package/tests/core/utilities/mocks/events.ts +0 -132
  241. package/tests/core/utilities/mocks/index.ts +0 -9
  242. package/tests/core/utilities/mocks/licenses.ts +0 -119
  243. package/tests/core/utilities/queue.ts +0 -9
  244. package/tests/core/utilities/structures/Chance.ts +0 -20
  245. package/tests/core/utilities/structures/accounts.ts +0 -80
  246. package/tests/core/utilities/structures/apps.ts +0 -21
  247. package/tests/core/utilities/structures/common.ts +0 -7
  248. package/tests/core/utilities/structures/db.ts +0 -12
  249. package/tests/core/utilities/structures/documents/index.ts +0 -1
  250. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  251. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  252. package/tests/core/utilities/structures/generator.ts +0 -3
  253. package/tests/core/utilities/structures/index.ts +0 -15
  254. package/tests/core/utilities/structures/koa.ts +0 -16
  255. package/tests/core/utilities/structures/licenses.ts +0 -190
  256. package/tests/core/utilities/structures/plugins.ts +0 -19
  257. package/tests/core/utilities/structures/quotas.ts +0 -72
  258. package/tests/core/utilities/structures/scim.ts +0 -80
  259. package/tests/core/utilities/structures/sso.ts +0 -118
  260. package/tests/core/utilities/structures/tenants.ts +0 -5
  261. package/tests/core/utilities/structures/userGroups.ts +0 -10
  262. package/tests/core/utilities/structures/users.ts +0 -89
  263. package/tests/core/utilities/testContainerUtils.ts +0 -165
  264. package/tests/core/utilities/utils/index.ts +0 -2
  265. package/tests/core/utilities/utils/queue.ts +0 -27
  266. package/tests/core/utilities/utils/time.ts +0 -3
  267. package/tests/extra/DBTestConfiguration.ts +0 -36
  268. package/tests/extra/index.ts +0 -2
  269. package/tests/extra/testEnv.ts +0 -95
  270. package/tests/index.ts +0 -2
  271. package/tests/jestEnv.ts +0 -10
  272. 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
- })