@backstage/plugin-catalog-backend-module-ldap 0.11.11-next.0 → 0.12.0
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.
- package/CHANGELOG.md +158 -0
- package/config.d.ts +10 -10
- package/dist/index.d.ts +15 -17
- package/dist/ldap/client.cjs.js +77 -125
- package/dist/ldap/client.cjs.js.map +1 -1
- package/dist/ldap/config.cjs.js +4 -2
- package/dist/ldap/config.cjs.js.map +1 -1
- package/dist/ldap/index.cjs.js +2 -2
- package/dist/ldap/read.cjs.js +10 -11
- package/dist/ldap/read.cjs.js.map +1 -1
- package/dist/ldap/util.cjs.js +0 -16
- package/dist/ldap/util.cjs.js.map +1 -1
- package/dist/ldap/vendors.cjs.js +1 -1
- package/dist/ldap/vendors.cjs.js.map +1 -1
- package/dist/module.cjs.js +2 -2
- package/dist/processors/LdapOrgReaderProcessor.cjs.js +0 -1
- package/dist/processors/LdapOrgReaderProcessor.cjs.js.map +1 -1
- package/package.json +10 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,163 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend-module-ldap
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 980f240: Moved from `ldapjs` dependency to `ldapts`
|
|
8
|
+
|
|
9
|
+
### Breaking Changes
|
|
10
|
+
|
|
11
|
+
**Type Migration**
|
|
12
|
+
|
|
13
|
+
Custom transformers must now accept `Entry` from `ldapts` instead of `SearchEntry`
|
|
14
|
+
from `ldapjs` The Entry type provides direct property access without need for
|
|
15
|
+
`.object()` or `.raw()` methods.
|
|
16
|
+
|
|
17
|
+
If you have custom user or group transformers, update the signature from:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
(vendor: LdapVendor, config: UserConfig, entry: SearchEntry) =>
|
|
21
|
+
Promise<UserEntity | undefined>;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
to
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
(vendor: LdapVendor, config: UserConfig, entry: Entry) =>
|
|
28
|
+
Promise<UserEntity | undefined>;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Search Options**
|
|
32
|
+
|
|
33
|
+
Updated LDAP search configuration `typesOnly: false` → `attributeValues: true`
|
|
34
|
+
This inverts the boolean logic: `ldapjs` used negative form while `ldapts` uses
|
|
35
|
+
positive form. Both achieve the same result: retrieving attribute values rather
|
|
36
|
+
than just attribute names.
|
|
37
|
+
|
|
38
|
+
Update LDAP search options in configuration from
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
options:
|
|
42
|
+
typesOnly: false
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
to
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
options:
|
|
49
|
+
attributeValues: true
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**API Changes** Removed `LdapClient.searchStreaming()` method. Users should
|
|
53
|
+
migrate to `LdapClient.search()` instead
|
|
54
|
+
|
|
55
|
+
If you're using `searchStreaming` directly:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Before
|
|
59
|
+
await client.searchStreaming(dn, options, async entry => {
|
|
60
|
+
// process each entry
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// After
|
|
64
|
+
const entries = await client.search(dn, options);
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
// process each entry
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> **_NOTE:_**: Both methods have always loaded all entries into memory. The
|
|
71
|
+
> `searchStreaming` method was only needed internally to handle `ldapjs`'s
|
|
72
|
+
> event-based API.
|
|
73
|
+
|
|
74
|
+
### Patch Changes
|
|
75
|
+
|
|
76
|
+
- 05f60e1: Refactored constructor parameter properties to explicit property declarations for compatibility with TypeScript's `erasableSyntaxOnly` setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.
|
|
77
|
+
- Updated dependencies
|
|
78
|
+
- @backstage/plugin-catalog-node@1.20.0
|
|
79
|
+
- @backstage/backend-plugin-api@1.5.0
|
|
80
|
+
- @backstage/config@1.3.6
|
|
81
|
+
- @backstage/catalog-model@1.7.6
|
|
82
|
+
- @backstage/plugin-catalog-common@1.1.7
|
|
83
|
+
|
|
84
|
+
## 0.12.0-next.1
|
|
85
|
+
|
|
86
|
+
### Minor Changes
|
|
87
|
+
|
|
88
|
+
- 980f240: Moved from `ldapjs` dependency to `ldapts`
|
|
89
|
+
|
|
90
|
+
### Breaking Changes
|
|
91
|
+
|
|
92
|
+
**Type Migration**
|
|
93
|
+
|
|
94
|
+
Custom transformers must now accept `Entry` from ldapts instead of `SearchEntry`
|
|
95
|
+
from ldapjs The Entry type provides direct property access without need for
|
|
96
|
+
`.object()` or `.raw()` methods.
|
|
97
|
+
|
|
98
|
+
If you have custom user or group transformers, update the signature from:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
(vendor: LdapVendor, config: UserConfig, entry: SearchEntry) =>
|
|
102
|
+
Promise<UserEntity | undefined>;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
to
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
(vendor: LdapVendor, config: UserConfig, entry: Entry) =>
|
|
109
|
+
Promise<UserEntity | undefined>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Search Options**
|
|
113
|
+
|
|
114
|
+
Updated LDAP search configuration `typesOnly: false` → `attributeValues: true`
|
|
115
|
+
This inverts the boolean logic: ldapjs used negative form while ldapts uses
|
|
116
|
+
positive form. Both achieve the same result: retrieving attribute values rather
|
|
117
|
+
than just attribute names.
|
|
118
|
+
|
|
119
|
+
Update LDAP search options in configuration from
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
options:
|
|
123
|
+
typesOnly: false
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
to
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
options:
|
|
130
|
+
attributeValues: true
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**API Changes** Removed `LdapClient.searchStreaming()` method. Users should
|
|
134
|
+
migrate to `LdapClient.search()` instead
|
|
135
|
+
|
|
136
|
+
If you're using `searchStreaming` directly:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Before
|
|
140
|
+
await client.searchStreaming(dn, options, async entry => {
|
|
141
|
+
// process each entry
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// After
|
|
145
|
+
const entries = await client.search(dn, options);
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
// process each entry
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
> **_NOTE:_**: Both methods have always loaded all entries into memory. The
|
|
152
|
+
> searchStreaming method was only needed internally to handle ldapjs's
|
|
153
|
+
> event-based API.
|
|
154
|
+
|
|
155
|
+
### Patch Changes
|
|
156
|
+
|
|
157
|
+
- Updated dependencies
|
|
158
|
+
- @backstage/plugin-catalog-node@1.20.0-next.1
|
|
159
|
+
- @backstage/backend-plugin-api@1.5.0-next.1
|
|
160
|
+
|
|
3
161
|
## 0.11.11-next.0
|
|
4
162
|
|
|
5
163
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -85,7 +85,7 @@ export interface Config {
|
|
|
85
85
|
sizeLimit?: number;
|
|
86
86
|
timeLimit?: number;
|
|
87
87
|
derefAliases?: number;
|
|
88
|
-
|
|
88
|
+
returnAttributeValues?: boolean;
|
|
89
89
|
paged?:
|
|
90
90
|
| boolean
|
|
91
91
|
| {
|
|
@@ -165,7 +165,7 @@ export interface Config {
|
|
|
165
165
|
sizeLimit?: number;
|
|
166
166
|
timeLimit?: number;
|
|
167
167
|
derefAliases?: number;
|
|
168
|
-
|
|
168
|
+
returnAttributeValues?: boolean;
|
|
169
169
|
paged?:
|
|
170
170
|
| boolean
|
|
171
171
|
| {
|
|
@@ -250,7 +250,7 @@ export interface Config {
|
|
|
250
250
|
sizeLimit?: number;
|
|
251
251
|
timeLimit?: number;
|
|
252
252
|
derefAliases?: number;
|
|
253
|
-
|
|
253
|
+
returnAttributeValues?: boolean;
|
|
254
254
|
paged?:
|
|
255
255
|
| boolean
|
|
256
256
|
| {
|
|
@@ -340,7 +340,7 @@ export interface Config {
|
|
|
340
340
|
sizeLimit?: number;
|
|
341
341
|
timeLimit?: number;
|
|
342
342
|
derefAliases?: number;
|
|
343
|
-
|
|
343
|
+
returnAttributeValues?: boolean;
|
|
344
344
|
paged?:
|
|
345
345
|
| boolean
|
|
346
346
|
| {
|
|
@@ -500,7 +500,7 @@ export interface Config {
|
|
|
500
500
|
sizeLimit?: number;
|
|
501
501
|
timeLimit?: number;
|
|
502
502
|
derefAliases?: number;
|
|
503
|
-
|
|
503
|
+
returnAttributeValues?: boolean;
|
|
504
504
|
paged?:
|
|
505
505
|
| boolean
|
|
506
506
|
| {
|
|
@@ -580,7 +580,7 @@ export interface Config {
|
|
|
580
580
|
sizeLimit?: number;
|
|
581
581
|
timeLimit?: number;
|
|
582
582
|
derefAliases?: number;
|
|
583
|
-
|
|
583
|
+
returnAttributeValues?: boolean;
|
|
584
584
|
paged?:
|
|
585
585
|
| boolean
|
|
586
586
|
| {
|
|
@@ -666,7 +666,7 @@ export interface Config {
|
|
|
666
666
|
sizeLimit?: number;
|
|
667
667
|
timeLimit?: number;
|
|
668
668
|
derefAliases?: number;
|
|
669
|
-
|
|
669
|
+
returnAttributeValues?: boolean;
|
|
670
670
|
paged?:
|
|
671
671
|
| boolean
|
|
672
672
|
| {
|
|
@@ -756,7 +756,7 @@ export interface Config {
|
|
|
756
756
|
sizeLimit?: number;
|
|
757
757
|
timeLimit?: number;
|
|
758
758
|
derefAliases?: number;
|
|
759
|
-
|
|
759
|
+
returnAttributeValues?: boolean;
|
|
760
760
|
paged?:
|
|
761
761
|
| boolean
|
|
762
762
|
| {
|
|
@@ -914,7 +914,7 @@ export interface Config {
|
|
|
914
914
|
sizeLimit?: number;
|
|
915
915
|
timeLimit?: number;
|
|
916
916
|
derefAliases?: number;
|
|
917
|
-
|
|
917
|
+
returnAttributeValues?: boolean;
|
|
918
918
|
paged?:
|
|
919
919
|
| boolean
|
|
920
920
|
| {
|
|
@@ -997,7 +997,7 @@ export interface Config {
|
|
|
997
997
|
sizeLimit?: number;
|
|
998
998
|
timeLimit?: number;
|
|
999
999
|
derefAliases?: number;
|
|
1000
|
-
|
|
1000
|
+
returnAttributeValues?: boolean;
|
|
1001
1001
|
paged?:
|
|
1002
1002
|
| boolean
|
|
1003
1003
|
| {
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EntityProvider, EntityProviderConnection, CatalogProcessor, CatalogProc
|
|
|
3
3
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
4
4
|
import { SchedulerServiceTaskScheduleDefinition, LoggerService, SchedulerServiceTaskRunner, SchedulerService } from '@backstage/backend-plugin-api';
|
|
5
5
|
import { JsonValue } from '@backstage/types';
|
|
6
|
-
import {
|
|
6
|
+
import { Entry, SearchOptions, Client, SearchResult } from 'ldapts';
|
|
7
7
|
import { UserEntity, GroupEntity } from '@backstage/catalog-model';
|
|
8
8
|
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
|
9
9
|
|
|
@@ -27,7 +27,7 @@ type LdapVendor = {
|
|
|
27
27
|
* @param entry - The ldap entry
|
|
28
28
|
* @param name - The attribute to decode
|
|
29
29
|
*/
|
|
30
|
-
decodeStringAttribute: (entry:
|
|
30
|
+
decodeStringAttribute: (entry: Entry, name: string) => string[];
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -163,15 +163,7 @@ declare class LdapClient {
|
|
|
163
163
|
* @param dn - The fully qualified base DN to search within
|
|
164
164
|
* @param options - The search options
|
|
165
165
|
*/
|
|
166
|
-
search(dn: string, options: SearchOptions): Promise<
|
|
167
|
-
/**
|
|
168
|
-
* Performs an LDAP search operation, calls a function on each entry to limit memory usage
|
|
169
|
-
*
|
|
170
|
-
* @param dn - The fully qualified base DN to search within
|
|
171
|
-
* @param options - The search options
|
|
172
|
-
* @param f - The callback to call on each search entry
|
|
173
|
-
*/
|
|
174
|
-
searchStreaming(dn: string, options: SearchOptions, f: (entry: SearchEntry) => Promise<void> | void): Promise<void>;
|
|
166
|
+
search(dn: string, options: SearchOptions): Promise<SearchResult>;
|
|
175
167
|
/**
|
|
176
168
|
* Get the Server Vendor.
|
|
177
169
|
* Currently only detects Microsoft Active Directory Servers.
|
|
@@ -179,12 +171,18 @@ declare class LdapClient {
|
|
|
179
171
|
* @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor
|
|
180
172
|
*/
|
|
181
173
|
getVendor(): Promise<LdapVendor>;
|
|
174
|
+
/**
|
|
175
|
+
* Check if the LDAP server is Google LDAP by examining RootDSE and schema
|
|
176
|
+
*/
|
|
177
|
+
private isGoogleLDAP;
|
|
178
|
+
private checkGoogleSchema;
|
|
179
|
+
private parseSchemaValues;
|
|
182
180
|
/**
|
|
183
181
|
* Get the Root DSE.
|
|
184
182
|
*
|
|
185
183
|
* @see https://ldapwiki.com/wiki/RootDSE
|
|
186
184
|
*/
|
|
187
|
-
getRootDSE(): Promise<
|
|
185
|
+
getRootDSE(): Promise<Entry | undefined>;
|
|
188
186
|
}
|
|
189
187
|
|
|
190
188
|
/**
|
|
@@ -201,7 +199,7 @@ declare class LdapClient {
|
|
|
201
199
|
*
|
|
202
200
|
* @public
|
|
203
201
|
*/
|
|
204
|
-
declare function mapStringAttr(entry:
|
|
202
|
+
declare function mapStringAttr(entry: Entry, vendor: LdapVendor, attributeName: string | undefined, setter: (value: string) => void): void;
|
|
205
203
|
|
|
206
204
|
/**
|
|
207
205
|
* The name of an entity annotation, that references the RDN of the LDAP object
|
|
@@ -253,7 +251,7 @@ declare const LDAP_UUID_ANNOTATION = "backstage.io/ldap-uuid";
|
|
|
253
251
|
*
|
|
254
252
|
* @public
|
|
255
253
|
*/
|
|
256
|
-
type UserTransformer = (vendor: LdapVendor, config: UserConfig, user:
|
|
254
|
+
type UserTransformer = (vendor: LdapVendor, config: UserConfig, user: Entry) => Promise<UserEntity | undefined>;
|
|
257
255
|
/**
|
|
258
256
|
* Customize the ingested Group entity
|
|
259
257
|
*
|
|
@@ -267,7 +265,7 @@ type UserTransformer = (vendor: LdapVendor, config: UserConfig, user: SearchEntr
|
|
|
267
265
|
*
|
|
268
266
|
* @public
|
|
269
267
|
*/
|
|
270
|
-
type GroupTransformer = (vendor: LdapVendor, config: GroupConfig, group:
|
|
268
|
+
type GroupTransformer = (vendor: LdapVendor, config: GroupConfig, group: Entry) => Promise<GroupEntity | undefined>;
|
|
271
269
|
|
|
272
270
|
/**
|
|
273
271
|
* The default implementation of the transformation from an LDAP entry to a
|
|
@@ -275,14 +273,14 @@ type GroupTransformer = (vendor: LdapVendor, config: GroupConfig, group: SearchE
|
|
|
275
273
|
*
|
|
276
274
|
* @public
|
|
277
275
|
*/
|
|
278
|
-
declare function defaultUserTransformer(vendor: LdapVendor, config: UserConfig, entry:
|
|
276
|
+
declare function defaultUserTransformer(vendor: LdapVendor, config: UserConfig, entry: Entry): Promise<UserEntity | undefined>;
|
|
279
277
|
/**
|
|
280
278
|
* The default implementation of the transformation from an LDAP entry to a
|
|
281
279
|
* Group entity.
|
|
282
280
|
*
|
|
283
281
|
* @public
|
|
284
282
|
*/
|
|
285
|
-
declare function defaultGroupTransformer(vendor: LdapVendor, config: GroupConfig, entry:
|
|
283
|
+
declare function defaultGroupTransformer(vendor: LdapVendor, config: GroupConfig, entry: Entry): Promise<GroupEntity | undefined>;
|
|
286
284
|
/**
|
|
287
285
|
* Reads users and groups out of an LDAP provider.
|
|
288
286
|
*
|
package/dist/ldap/client.cjs.js
CHANGED
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var errors = require('@backstage/errors');
|
|
4
4
|
var promises = require('fs/promises');
|
|
5
|
-
var
|
|
6
|
-
var lodash = require('lodash');
|
|
5
|
+
var ldapts = require('ldapts');
|
|
7
6
|
var tlsLib = require('tls');
|
|
8
|
-
var util = require('./util.cjs.js');
|
|
9
7
|
var vendors = require('./vendors.cjs.js');
|
|
10
8
|
|
|
11
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
12
10
|
|
|
13
|
-
var ldap__default = /*#__PURE__*/_interopDefaultCompat(ldap);
|
|
14
11
|
var tlsLib__default = /*#__PURE__*/_interopDefaultCompat(tlsLib);
|
|
15
12
|
|
|
16
13
|
class LdapClient {
|
|
@@ -25,29 +22,27 @@ class LdapClient {
|
|
|
25
22
|
key
|
|
26
23
|
});
|
|
27
24
|
}
|
|
28
|
-
const
|
|
25
|
+
const tlsOptions = {
|
|
26
|
+
secureContext,
|
|
27
|
+
rejectUnauthorized: tls?.rejectUnauthorized
|
|
28
|
+
};
|
|
29
|
+
const client = new ldapts.Client({
|
|
29
30
|
url: target,
|
|
30
|
-
tlsOptions:
|
|
31
|
-
secureContext,
|
|
32
|
-
rejectUnauthorized: tls?.rejectUnauthorized
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
client.on("error", (err) => {
|
|
36
|
-
logger.warn(`LDAP client threw an error, ${util.errorString(err)}`);
|
|
31
|
+
...Object.values(tlsOptions).some((v) => v !== void 0) ? { tlsOptions } : void 0
|
|
37
32
|
});
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const ldapClient = new LdapClient(client, logger);
|
|
34
|
+
if (bind) {
|
|
35
|
+
try {
|
|
36
|
+
await client.bind(bind.dn, bind.secret);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
await client.unbind();
|
|
39
|
+
throw new errors.ForwardedError(
|
|
40
|
+
`LDAP bind failed for ${bind.dn}, ${error}`,
|
|
41
|
+
error
|
|
42
|
+
);
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
|
-
return
|
|
42
|
-
const { dn, secret } = bind;
|
|
43
|
-
client.bind(dn, secret, (err) => {
|
|
44
|
-
if (err) {
|
|
45
|
-
reject(`LDAP bind failed for ${dn}, ${util.errorString(err)}`);
|
|
46
|
-
} else {
|
|
47
|
-
resolve(new LdapClient(client, logger));
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
});
|
|
45
|
+
return ldapClient;
|
|
51
46
|
}
|
|
52
47
|
client;
|
|
53
48
|
logger;
|
|
@@ -62,99 +57,19 @@ class LdapClient {
|
|
|
62
57
|
* @param options - The search options
|
|
63
58
|
*/
|
|
64
59
|
async search(dn, options) {
|
|
60
|
+
this.logger.debug(`Reading LDAP entries so far`);
|
|
65
61
|
try {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.logger.warn("Received unsupported search referral");
|
|
78
|
-
});
|
|
79
|
-
res.on("searchEntry", (entry) => {
|
|
80
|
-
output.push(entry);
|
|
81
|
-
});
|
|
82
|
-
res.on("error", (e) => {
|
|
83
|
-
reject(new Error(util.errorString(e)));
|
|
84
|
-
});
|
|
85
|
-
res.on("page", (_result, cb) => {
|
|
86
|
-
if (cb) {
|
|
87
|
-
cb();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
res.on("end", (r) => {
|
|
91
|
-
if (!r) {
|
|
92
|
-
reject(new Error("Null response"));
|
|
93
|
-
} else if (r.status !== 0) {
|
|
94
|
-
reject(new Error(`Got status ${r.status}: ${r.errorMessage}`));
|
|
95
|
-
} else {
|
|
96
|
-
resolve(output);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
return await search.finally(() => {
|
|
102
|
-
clearInterval(logInterval);
|
|
103
|
-
});
|
|
104
|
-
} catch (e) {
|
|
105
|
-
throw new errors.ForwardedError(`LDAP search at DN "${dn}" failed`, e);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Performs an LDAP search operation, calls a function on each entry to limit memory usage
|
|
110
|
-
*
|
|
111
|
-
* @param dn - The fully qualified base DN to search within
|
|
112
|
-
* @param options - The search options
|
|
113
|
-
* @param f - The callback to call on each search entry
|
|
114
|
-
*/
|
|
115
|
-
async searchStreaming(dn, options, f) {
|
|
116
|
-
try {
|
|
117
|
-
return await new Promise((resolve, reject) => {
|
|
118
|
-
this.client.search(dn, util.createOptions(options), (err, res) => {
|
|
119
|
-
if (err) {
|
|
120
|
-
reject(new Error(util.errorString(err)));
|
|
121
|
-
}
|
|
122
|
-
let awaitList = [];
|
|
123
|
-
let transformError = false;
|
|
124
|
-
const transformReject = (e) => {
|
|
125
|
-
transformError = true;
|
|
126
|
-
reject(
|
|
127
|
-
new Error(
|
|
128
|
-
`Transform function threw an exception, ${errors.stringifyError(e)}`
|
|
129
|
-
)
|
|
130
|
-
);
|
|
131
|
-
};
|
|
132
|
-
res.on("searchReference", () => {
|
|
133
|
-
this.logger.warn("Received unsupported search referral");
|
|
134
|
-
});
|
|
135
|
-
res.on("searchEntry", (entry) => {
|
|
136
|
-
if (!transformError) awaitList.push(f(entry));
|
|
137
|
-
});
|
|
138
|
-
res.on("page", (_, cb) => {
|
|
139
|
-
Promise.all(awaitList).then(() => {
|
|
140
|
-
awaitList = [];
|
|
141
|
-
if (cb) cb();
|
|
142
|
-
}).catch(transformReject);
|
|
143
|
-
});
|
|
144
|
-
res.on("error", (e) => {
|
|
145
|
-
reject(new Error(util.errorString(e)));
|
|
146
|
-
});
|
|
147
|
-
res.on("end", (r) => {
|
|
148
|
-
if (!r) {
|
|
149
|
-
throw new Error("Null response");
|
|
150
|
-
} else if (r.status !== 0) {
|
|
151
|
-
throw new Error(`Got status ${r.status}: ${r.errorMessage}`);
|
|
152
|
-
} else {
|
|
153
|
-
Promise.all(awaitList).then(() => resolve()).catch(transformReject);
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
});
|
|
62
|
+
const ldaptsOptions = {
|
|
63
|
+
scope: options.scope,
|
|
64
|
+
filter: options.filter,
|
|
65
|
+
attributes: options.attributes,
|
|
66
|
+
sizeLimit: options.sizeLimit,
|
|
67
|
+
timeLimit: options.timeLimit,
|
|
68
|
+
derefAliases: options.derefAliases,
|
|
69
|
+
paged: options.paged
|
|
70
|
+
};
|
|
71
|
+
const result = await this.client.search(dn, ldaptsOptions);
|
|
72
|
+
return result;
|
|
158
73
|
} catch (e) {
|
|
159
74
|
throw new errors.ForwardedError(`LDAP search at DN "${dn}" failed`, e);
|
|
160
75
|
}
|
|
@@ -169,17 +84,16 @@ class LdapClient {
|
|
|
169
84
|
if (this.vendor) {
|
|
170
85
|
return this.vendor;
|
|
171
86
|
}
|
|
172
|
-
const clientHost = this.client?.host || "";
|
|
173
87
|
this.vendor = this.getRootDSE().then((root) => {
|
|
174
|
-
if (root && root.
|
|
88
|
+
if (root && root.forestFunctionality) {
|
|
175
89
|
return vendors.ActiveDirectoryVendor;
|
|
176
|
-
} else if (root && root.
|
|
90
|
+
} else if (root && root.ipaDomainLevel) {
|
|
177
91
|
return vendors.FreeIpaVendor;
|
|
178
|
-
} else if (root && "aeRoot" in root
|
|
92
|
+
} else if (root && "aeRoot" in root) {
|
|
179
93
|
return vendors.AEDirVendor;
|
|
180
|
-
} else if (
|
|
94
|
+
} else if (this.isGoogleLDAP(root)) {
|
|
181
95
|
return vendors.GoogleLdapVendor;
|
|
182
|
-
} else if (root && root.
|
|
96
|
+
} else if (root && root.vendorName?.toString() === "LLDAP") {
|
|
183
97
|
return vendors.LLDAPVendor;
|
|
184
98
|
}
|
|
185
99
|
return vendors.DefaultLdapVendor;
|
|
@@ -189,18 +103,56 @@ class LdapClient {
|
|
|
189
103
|
});
|
|
190
104
|
return this.vendor;
|
|
191
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if the LDAP server is Google LDAP by examining RootDSE and schema
|
|
108
|
+
*/
|
|
109
|
+
isGoogleLDAP(rootDSE) {
|
|
110
|
+
if (!rootDSE) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const hasGoogleRootDSEPattern = !rootDSE.namingContexts && // No namingContexts
|
|
114
|
+
!rootDSE.supportedControl && // No supportedControl
|
|
115
|
+
!rootDSE.vendorName && // No vendor info
|
|
116
|
+
!rootDSE.vendorVersion && rootDSE.subschemaSubentry === "cn=subschema";
|
|
117
|
+
if (!hasGoogleRootDSEPattern) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const schemaHasGoogleAttributes = this.checkGoogleSchema(rootDSE);
|
|
122
|
+
return schemaHasGoogleAttributes;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new errors.ForwardedError("Schema check failed", error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Check a shema for Google-specific patterns
|
|
128
|
+
checkGoogleSchema(rootDSE) {
|
|
129
|
+
try {
|
|
130
|
+
const objectClasses = this.parseSchemaValues(rootDSE.objectClasses);
|
|
131
|
+
const attributeTypes = this.parseSchemaValues(rootDSE.attributeTypes);
|
|
132
|
+
const hasGoogleAttributes = objectClasses.some((oc) => oc.includes("googleUid")) || attributeTypes.some((at) => at.includes("googleAdminCreated"));
|
|
133
|
+
return hasGoogleAttributes;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
this.logger.warn("Error checking schema:", error);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
parseSchemaValues(schemaValue) {
|
|
140
|
+
if (!schemaValue) return [];
|
|
141
|
+
const values = Array.isArray(schemaValue) ? schemaValue : [schemaValue];
|
|
142
|
+
return values.map((v) => v.toString());
|
|
143
|
+
}
|
|
192
144
|
/**
|
|
193
145
|
* Get the Root DSE.
|
|
194
146
|
*
|
|
195
147
|
* @see https://ldapwiki.com/wiki/RootDSE
|
|
196
148
|
*/
|
|
197
149
|
async getRootDSE() {
|
|
198
|
-
const result = await this.search("", {
|
|
150
|
+
const result = await this.client.search("", {
|
|
199
151
|
scope: "base",
|
|
200
152
|
filter: "(objectclass=*)"
|
|
201
153
|
});
|
|
202
|
-
if (result && result.length === 1) {
|
|
203
|
-
return result[0];
|
|
154
|
+
if (result && result.searchEntries.length === 1) {
|
|
155
|
+
return result.searchEntries[0];
|
|
204
156
|
}
|
|
205
157
|
return void 0;
|
|
206
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs.js","sources":["../../src/ldap/client.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError, stringifyError } from '@backstage/errors';\nimport { readFile } from 'fs/promises';\nimport ldap, { Client, SearchEntry, SearchOptions } from 'ldapjs';\nimport { cloneDeep } from 'lodash';\nimport tlsLib from 'tls';\nimport { BindConfig, TLSConfig } from './config';\nimport { createOptions, errorString } from './util';\nimport {\n AEDirVendor,\n ActiveDirectoryVendor,\n DefaultLdapVendor,\n GoogleLdapVendor,\n LLDAPVendor,\n FreeIpaVendor,\n LdapVendor,\n} from './vendors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Basic wrapper for the `ldapjs` library.\n *\n * Helps out with promisifying calls, paging, binding etc.\n *\n * @public\n */\nexport class LdapClient {\n private vendor: Promise<LdapVendor> | undefined;\n\n static async create(\n logger: LoggerService,\n target: string,\n bind?: BindConfig,\n tls?: TLSConfig,\n ): Promise<LdapClient> {\n let secureContext;\n if (tls && tls.certs && tls.keys) {\n const cert = await readFile(tls.certs, 'utf-8');\n const key = await readFile(tls.keys, 'utf-8');\n secureContext = tlsLib.createSecureContext({\n cert: cert,\n key: key,\n });\n }\n\n const client = ldap.createClient({\n url: target,\n tlsOptions: {\n secureContext,\n rejectUnauthorized: tls?.rejectUnauthorized,\n },\n });\n\n // We want to have a catch-all error handler at the top, since the default\n // behavior of the client is to blow up the entire process when it fails,\n // unless an error handler is set.\n client.on('error', (err: ldap.Error) => {\n logger.warn(`LDAP client threw an error, ${errorString(err)}`);\n });\n\n if (!bind) {\n return new LdapClient(client, logger);\n }\n\n return new Promise<LdapClient>((resolve, reject) => {\n const { dn, secret } = bind;\n client.bind(dn, secret, err => {\n if (err) {\n reject(`LDAP bind failed for ${dn}, ${errorString(err)}`);\n } else {\n resolve(new LdapClient(client, logger));\n }\n });\n });\n }\n\n private readonly client: Client;\n private readonly logger: LoggerService;\n\n constructor(client: Client, logger: LoggerService) {\n this.client = client;\n this.logger = logger;\n }\n\n /**\n * Performs an LDAP search operation.\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n */\n async search(dn: string, options: SearchOptions): Promise<SearchEntry[]> {\n try {\n const output: SearchEntry[] = [];\n\n const logInterval = setInterval(() => {\n this.logger.debug(`Read ${output.length} LDAP entries so far...`);\n }, 5000);\n\n const search = new Promise<SearchEntry[]>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, cloneDeep(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n return;\n }\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n output.push(entry);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('page', (_result, cb) => {\n if (cb) {\n cb();\n }\n });\n\n res.on('end', r => {\n if (!r) {\n reject(new Error('Null response'));\n } else if (r.status !== 0) {\n reject(new Error(`Got status ${r.status}: ${r.errorMessage}`));\n } else {\n resolve(output);\n }\n });\n });\n });\n\n return await search.finally(() => {\n clearInterval(logInterval);\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Performs an LDAP search operation, calls a function on each entry to limit memory usage\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n * @param f - The callback to call on each search entry\n */\n async searchStreaming(\n dn: string,\n options: SearchOptions,\n f: (entry: SearchEntry) => Promise<void> | void,\n ): Promise<void> {\n try {\n return await new Promise<void>((resolve, reject) => {\n // Note that we clone the (frozen) options, since ldapjs rudely tries to\n // overwrite parts of them\n this.client.search(dn, createOptions(options), (err, res) => {\n if (err) {\n reject(new Error(errorString(err)));\n }\n let awaitList: Array<Promise<void> | void> = [];\n let transformError = false;\n\n const transformReject = (e: Error) => {\n transformError = true;\n reject(\n new Error(\n `Transform function threw an exception, ${stringifyError(e)}`,\n ),\n );\n };\n\n res.on('searchReference', () => {\n this.logger.warn('Received unsupported search referral');\n });\n\n res.on('searchEntry', entry => {\n if (!transformError) awaitList.push(f(entry));\n });\n\n res.on('page', (_, cb) => {\n // awaits completion before fetching next page\n Promise.all(awaitList)\n .then(() => {\n // flush list\n awaitList = [];\n if (cb) cb();\n })\n .catch(transformReject);\n });\n\n res.on('error', e => {\n reject(new Error(errorString(e)));\n });\n\n res.on('end', r => {\n if (!r) {\n throw new Error('Null response');\n } else if (r.status !== 0) {\n throw new Error(`Got status ${r.status}: ${r.errorMessage}`);\n } else {\n Promise.all(awaitList)\n .then(() => resolve())\n .catch(transformReject);\n }\n });\n });\n });\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Get the Server Vendor.\n * Currently only detects Microsoft Active Directory Servers.\n *\n * @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor\n */\n async getVendor(): Promise<LdapVendor> {\n if (this.vendor) {\n return this.vendor;\n }\n const clientHost = this.client?.host || '';\n this.vendor = this.getRootDSE()\n .then(root => {\n if (root && root.raw?.forestFunctionality) {\n return ActiveDirectoryVendor;\n } else if (root && root.raw?.ipaDomainLevel) {\n return FreeIpaVendor;\n } else if (root && 'aeRoot' in root.raw) {\n return AEDirVendor;\n } else if (clientHost === 'ldap.google.com') {\n return GoogleLdapVendor;\n } else if (root && root.raw?.vendorName?.toString() === 'LLDAP') {\n return LLDAPVendor;\n }\n return DefaultLdapVendor;\n })\n .catch(err => {\n this.vendor = undefined;\n throw err;\n });\n return this.vendor;\n }\n\n /**\n * Get the Root DSE.\n *\n * @see https://ldapwiki.com/wiki/RootDSE\n */\n async getRootDSE(): Promise<SearchEntry | undefined> {\n const result = await this.search('', {\n scope: 'base',\n filter: '(objectclass=*)',\n } as SearchOptions);\n if (result && result.length === 1) {\n return result[0];\n }\n return undefined;\n }\n}\n"],"names":["readFile","tlsLib","ldap","errorString","cloneDeep","ForwardedError","createOptions","stringifyError","ActiveDirectoryVendor","FreeIpaVendor","AEDirVendor","GoogleLdapVendor","LLDAPVendor","DefaultLdapVendor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.cjs.js","sources":["../../src/ldap/client.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ForwardedError } from '@backstage/errors';\nimport { readFile } from 'fs/promises';\nimport { Client, Entry, SearchOptions, SearchResult } from 'ldapts';\nimport tlsLib from 'tls';\nimport { BindConfig, TLSConfig } from './config';\nimport {\n AEDirVendor,\n ActiveDirectoryVendor,\n DefaultLdapVendor,\n LLDAPVendor,\n FreeIpaVendor,\n LdapVendor,\n GoogleLdapVendor,\n} from './vendors';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Basic wrapper for the `ldapjs` library.\n *\n * Helps out with promisifying calls, paging, binding etc.\n *\n * @public\n */\n\nexport class LdapClient {\n private vendor: Promise<LdapVendor> | undefined;\n\n static async create(\n logger: LoggerService,\n target: string,\n bind?: BindConfig,\n tls?: TLSConfig,\n ): Promise<LdapClient> {\n let secureContext;\n if (tls && tls.certs && tls.keys) {\n const cert = await readFile(tls.certs, 'utf-8');\n const key = await readFile(tls.keys, 'utf-8');\n secureContext = tlsLib.createSecureContext({\n cert: cert,\n key: key,\n });\n }\n const tlsOptions: tlsLib.ConnectionOptions = {\n secureContext,\n rejectUnauthorized: tls?.rejectUnauthorized,\n };\n const client = new Client({\n url: target,\n ...(Object.values(tlsOptions).some(v => v !== undefined)\n ? { tlsOptions }\n : undefined),\n });\n\n const ldapClient = new LdapClient(client, logger);\n\n if (bind) {\n try {\n await client.bind(bind.dn, bind.secret);\n } catch (error) {\n await client.unbind();\n throw new ForwardedError(\n `LDAP bind failed for ${bind.dn}, ${error}`,\n error,\n );\n }\n }\n return ldapClient;\n }\n\n private readonly client: Client;\n private readonly logger: LoggerService;\n\n constructor(client: Client, logger: LoggerService) {\n this.client = client;\n this.logger = logger;\n }\n\n /**\n * Performs an LDAP search operation.\n *\n * @param dn - The fully qualified base DN to search within\n * @param options - The search options\n */\n async search(dn: string, options: SearchOptions): Promise<SearchResult> {\n this.logger.debug(`Reading LDAP entries so far`);\n try {\n const ldaptsOptions: SearchOptions = {\n scope: options.scope,\n filter: options.filter,\n attributes: options.attributes,\n sizeLimit: options.sizeLimit,\n timeLimit: options.timeLimit,\n derefAliases: options.derefAliases,\n paged: options.paged,\n };\n\n const result = await this.client.search(dn, ldaptsOptions);\n\n return result;\n } catch (e) {\n throw new ForwardedError(`LDAP search at DN \"${dn}\" failed`, e);\n }\n }\n\n /**\n * Get the Server Vendor.\n * Currently only detects Microsoft Active Directory Servers.\n *\n * @see https://ldapwiki.com/wiki/Determine%20LDAP%20Server%20Vendor\n */\n async getVendor(): Promise<LdapVendor> {\n if (this.vendor) {\n return this.vendor;\n }\n // const clientHost = this.client?.host || '';\n this.vendor = this.getRootDSE()\n .then(root => {\n if (root && root.forestFunctionality) {\n return ActiveDirectoryVendor;\n } else if (root && root.ipaDomainLevel) {\n return FreeIpaVendor;\n } else if (root && 'aeRoot' in root) {\n return AEDirVendor;\n } else if (this.isGoogleLDAP(root)) {\n return GoogleLdapVendor;\n } else if (root && root.vendorName?.toString() === 'LLDAP') {\n return LLDAPVendor;\n }\n return DefaultLdapVendor;\n })\n .catch(err => {\n this.vendor = undefined;\n throw err;\n });\n return this.vendor;\n }\n\n /**\n * Check if the LDAP server is Google LDAP by examining RootDSE and schema\n */\n private isGoogleLDAP(rootDSE: Entry | undefined): boolean {\n if (!rootDSE) {\n return false;\n }\n\n // RootDSE characteristics\n const hasGoogleRootDSEPattern =\n !rootDSE.namingContexts && // No namingContexts\n !rootDSE.supportedControl && // No supportedControl\n !rootDSE.vendorName && // No vendor info\n !rootDSE.vendorVersion &&\n rootDSE.subschemaSubentry === 'cn=subschema';\n\n if (!hasGoogleRootDSEPattern) {\n return false;\n }\n\n try {\n const schemaHasGoogleAttributes = this.checkGoogleSchema(rootDSE);\n return schemaHasGoogleAttributes;\n } catch (error) {\n throw new ForwardedError('Schema check failed', error);\n }\n }\n\n // Check a shema for Google-specific patterns\n private checkGoogleSchema(rootDSE: Entry): boolean {\n try {\n const objectClasses = this.parseSchemaValues(rootDSE.objectClasses);\n const attributeTypes = this.parseSchemaValues(rootDSE.attributeTypes);\n\n // Check if any Google-specific attributes are present\n const hasGoogleAttributes =\n objectClasses.some(oc => oc.includes('googleUid')) ||\n attributeTypes.some(at => at.includes('googleAdminCreated'));\n\n return hasGoogleAttributes;\n } catch (error) {\n this.logger.warn('Error checking schema:', error);\n return false;\n }\n }\n\n private parseSchemaValues(\n schemaValue: Buffer | Buffer[] | string[] | string,\n ): string[] {\n if (!schemaValue) return [];\n\n const values = Array.isArray(schemaValue) ? schemaValue : [schemaValue];\n return values.map(v => v.toString());\n }\n\n /**\n * Get the Root DSE.\n *\n * @see https://ldapwiki.com/wiki/RootDSE\n */\n async getRootDSE(): Promise<Entry | undefined> {\n const result = await this.client.search('', {\n scope: 'base',\n filter: '(objectclass=*)',\n } as SearchOptions);\n if (result && result.searchEntries.length === 1) {\n return result.searchEntries[0];\n }\n return undefined;\n }\n}\n"],"names":["readFile","tlsLib","Client","ForwardedError","ActiveDirectoryVendor","FreeIpaVendor","AEDirVendor","GoogleLdapVendor","LLDAPVendor","DefaultLdapVendor"],"mappings":"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"}
|
package/dist/ldap/config.cjs.js
CHANGED
|
@@ -83,8 +83,10 @@ function readOptionsConfig(c) {
|
|
|
83
83
|
attributes: c.getOptionalStringArray("attributes"),
|
|
84
84
|
sizeLimit: c.getOptionalNumber("sizeLimit"),
|
|
85
85
|
timeLimit: c.getOptionalNumber("timeLimit"),
|
|
86
|
-
derefAliases: c.getOptionalNumber(
|
|
87
|
-
|
|
86
|
+
derefAliases: c.getOptionalNumber(
|
|
87
|
+
"derefAliases"
|
|
88
|
+
),
|
|
89
|
+
returnAttributeValues: c.getOptionalBoolean("attributeValues"),
|
|
88
90
|
...paged !== void 0 ? { paged } : void 0
|
|
89
91
|
};
|
|
90
92
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.cjs.js","sources":["../../src/ldap/config.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SchedulerServiceTaskScheduleDefinition,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { SearchOptions } from 'ldapjs';\nimport mergeWith from 'lodash/mergeWith';\nimport { trimEnd } from 'lodash';\nimport { RecursivePartial } from './util';\n\n/**\n * The configuration parameters for a single LDAP provider.\n *\n * @public\n */\nexport type LdapProviderConfig = {\n // The id of the\n id: string;\n // The prefix of the target that this matches on, e.g.\n // \"ldaps://ds.example.net\", with no trailing slash.\n target: string;\n // TLS settings\n tls?: TLSConfig;\n // The settings to use for the bind command. If none are specified, the bind\n // command is not issued.\n bind?: BindConfig;\n // The settings that govern the reading and interpretation of users\n users: UserConfig[];\n // The settings that govern the reading and interpretation of groups\n groups: GroupConfig[];\n // Schedule configuration for refresh tasks.\n schedule?: SchedulerServiceTaskScheduleDefinition;\n // Configuration for overriding the vendor-specific default attribute names.\n vendor?: VendorConfig;\n};\n\n/**\n * TLS settings\n *\n * @public\n */\nexport type TLSConfig = {\n // Node TLS rejectUnauthorized\n rejectUnauthorized?: boolean;\n // A file containing private keys in PEM format\n keys?: string;\n // A file containing cert chains in PEM format\n certs?: string;\n};\n\n/**\n * The settings to use for the a command.\n *\n * @public\n */\nexport type BindConfig = {\n // The DN of the user to auth as, e.g.\n // uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net\n dn: string;\n // The secret of the user to auth as (its password)\n secret: string;\n};\n\n/**\n * The settings that govern the reading and interpretation of users.\n *\n * @public\n */\nexport type UserConfig = {\n // The DN under which users are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported. The\n // default is scope \"one\" and attributes \"*\" and \"+\".\n options: SearchOptions;\n\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"uid\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"uid\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity.\n description?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity. Defaults to \"mail\".\n email: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.memberOf field of the entity. Defaults to \"memberOf\".\n memberOf: string | null;\n };\n};\n\n/**\n * The settings that govern the reading and interpretation of groups.\n *\n * @public\n */\nexport type GroupConfig = {\n // The DN under which groups are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported.\n options: SearchOptions;\n\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"cn\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"cn\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity. Defaults to \"description\".\n description: string;\n // The name of the attribute that shall be used for the value of the\n // spec.type field of the entity. Defaults to \"groupType\".\n type: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity.\n email?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.parent field of the entity. Defaults to \"memberOf\".\n memberOf: string | null;\n // The name of the attribute that shall be used for the values of the\n // spec.children field of the entity. Defaults to \"member\".\n members: string | null;\n };\n};\n\n/**\n * Configuration for LDAP vendor-specific attributes.\n *\n * Allows custom attribute names for distinguished names (DN) and\n * universally unique identifiers (UUID) in LDAP directories.\n *\n * @public\n */\nexport type VendorConfig = {\n /**\n * Attribute name for the distinguished name (DN) of an entry,\n */\n dnAttributeName?: string;\n\n /**\n * Attribute name for the unique identifier (UUID) of an entry,\n */\n uuidAttributeName?: string;\n};\n\nconst defaultUserConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'uid',\n name: 'uid',\n displayName: 'cn',\n email: 'mail',\n memberOf: 'memberOf',\n },\n};\n\nconst defaultGroupConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'cn',\n name: 'cn',\n description: 'description',\n displayName: 'cn',\n type: 'groupType',\n memberOf: 'memberOf',\n members: 'member',\n },\n};\n\nfunction freeze<T>(data: T): T {\n return JSON.parse(JSON.stringify(data), (_key, value) => {\n if (typeof value === 'object' && value !== null) {\n Object.freeze(value);\n }\n return value;\n });\n}\n\nfunction readTlsConfig(\n c: Config | undefined,\n): LdapProviderConfig['tls'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n rejectUnauthorized: c.getOptionalBoolean('rejectUnauthorized'),\n keys: c.getOptionalString('keys'),\n certs: c.getOptionalString('certs'),\n };\n}\n\nfunction readBindConfig(\n c: Config | undefined,\n): LdapProviderConfig['bind'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dn: c.getString('dn'),\n secret: c.getString('secret'),\n };\n}\n\nfunction readVendorConfig(\n c: Config | undefined,\n): LdapProviderConfig['vendor'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dnAttributeName: c.getOptionalString('dnAttributeName'),\n uuidAttributeName: c.getOptionalString('uuidAttributeName'),\n };\n}\n\nfunction readOptionsConfig(c: Config | undefined): SearchOptions {\n if (!c) {\n return {};\n }\n\n const paged = readOptionsPagedConfig(c);\n\n return {\n scope: c.getOptionalString('scope') as SearchOptions['scope'],\n filter: formatFilter(c.getOptionalString('filter')),\n attributes: c.getOptionalStringArray('attributes'),\n sizeLimit: c.getOptionalNumber('sizeLimit'),\n timeLimit: c.getOptionalNumber('timeLimit'),\n derefAliases: c.getOptionalNumber('derefAliases'),\n typesOnly: c.getOptionalBoolean('typesOnly'),\n ...(paged !== undefined ? { paged } : undefined),\n };\n}\n\nfunction readOptionsPagedConfig(c: Config): SearchOptions['paged'] {\n const pagedConfig = c.getOptional('paged');\n if (pagedConfig === undefined) {\n return undefined;\n }\n\n if (pagedConfig === true || pagedConfig === false) {\n return pagedConfig;\n }\n\n const pageSize = c.getOptionalNumber('paged.pageSize');\n const pagePause = c.getOptionalBoolean('paged.pagePause');\n return {\n ...(pageSize !== undefined ? { pageSize } : undefined),\n ...(pagePause !== undefined ? { pagePause } : undefined),\n };\n}\n\nfunction readSetConfig(\n c: Config | undefined,\n): { [path: string]: JsonValue } | undefined {\n if (!c) {\n return undefined;\n }\n return c.get();\n}\n\nfunction readUserMapConfig(c: Config | undefined): Partial<UserConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n };\n}\n\nfunction readGroupMapConfig(\n c: Config | undefined,\n): Partial<GroupConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n type: c.getOptionalString('type'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n members: c.getOptionalString('members'),\n };\n}\n\nfunction readUserConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['users']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleUserConfig(it));\n }\n return [readSingleUserConfig(c)];\n}\n\nfunction readSingleUserConfig(c: Config): RecursivePartial<UserConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readUserMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction readGroupConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['groups']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleGroupConfig(it));\n }\n return [readSingleGroupConfig(c)];\n}\n\nfunction readSingleGroupConfig(c: Config): RecursivePartial<GroupConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readGroupMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction formatFilter(filter?: string): string | undefined {\n // Remove extra whitespace between blocks to support multiline filters from the configuration\n return filter?.replace(/\\s*(\\(|\\))/g, '$1')?.trim();\n}\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n * @deprecated This exists for backwards compatibility only and will be removed in the future.\n */\nexport function readLdapLegacyConfig(config: Config): LdapProviderConfig[] {\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n return providerConfigs.map(c => {\n const newConfig = {\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(c.getConfig('users')).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(c.getConfig('groups')).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\n/**\n * Parses all configured providers.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n */\nexport function readProviderConfigs(config: Config): LdapProviderConfig[] {\n const providersConfig = config.getOptionalConfig('catalog.providers.ldapOrg');\n if (!providersConfig) {\n return [];\n }\n\n return providersConfig.keys().map(id => {\n const c = providersConfig.getConfig(id);\n const schedule = c.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n c.getConfig('schedule'),\n )\n : undefined;\n\n const isUserList = Array.isArray(c.getOptional('users'));\n const isGroupList = Array.isArray(c.getOptional('groups'));\n\n const newConfig = {\n id,\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(\n isUserList\n ? c.getOptionalConfigArray('users')\n : c.getOptionalConfig('users'),\n ).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(\n isGroupList\n ? c.getOptionalConfigArray('groups')\n : c.getOptionalConfig('groups'),\n ).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n schedule,\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\nfunction replaceArraysIfPresent(_into: any, from: any) {\n // Replace arrays instead of merging, otherwise default behavior\n return Array.isArray(from) ? from : undefined;\n}\n"],"names":["trimEnd","mergeWith","readSchedulerServiceTaskScheduleDefinitionFromConfig"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.cjs.js","sources":["../../src/ldap/config.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SchedulerServiceTaskScheduleDefinition,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { JsonValue } from '@backstage/types';\nimport { SearchOptions } from 'ldapts';\nimport mergeWith from 'lodash/mergeWith';\nimport { trimEnd } from 'lodash';\nimport { RecursivePartial } from './util';\n\n/**\n * The configuration parameters for a single LDAP provider.\n *\n * @public\n */\nexport type LdapProviderConfig = {\n // The id of the\n id: string;\n // The prefix of the target that this matches on, e.g.\n // \"ldaps://ds.example.net\", with no trailing slash.\n target: string;\n // TLS settings\n tls?: TLSConfig;\n // The settings to use for the bind command. If none are specified, the bind\n // command is not issued.\n bind?: BindConfig;\n // The settings that govern the reading and interpretation of users\n users: UserConfig[];\n // The settings that govern the reading and interpretation of groups\n groups: GroupConfig[];\n // Schedule configuration for refresh tasks.\n schedule?: SchedulerServiceTaskScheduleDefinition;\n // Configuration for overriding the vendor-specific default attribute names.\n vendor?: VendorConfig;\n};\n\n/**\n * TLS settings\n *\n * @public\n */\nexport type TLSConfig = {\n // Node TLS rejectUnauthorized\n rejectUnauthorized?: boolean;\n // A file containing private keys in PEM format\n keys?: string;\n // A file containing cert chains in PEM format\n certs?: string;\n};\n\n/**\n * The settings to use for the a command.\n *\n * @public\n */\nexport type BindConfig = {\n // The DN of the user to auth as, e.g.\n // uid=ldap-robot,ou=robots,ou=example,dc=example,dc=net\n dn: string;\n // The secret of the user to auth as (its password)\n secret: string;\n};\n\n/**\n * The settings that govern the reading and interpretation of users.\n *\n * @public\n */\nexport type UserConfig = {\n // The DN under which users are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported. The\n // default is scope \"one\" and attributes \"*\" and \"+\".\n options: SearchOptions;\n\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"uid\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"uid\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity.\n description?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity. Defaults to \"mail\".\n email: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.memberOf field of the entity. Defaults to \"memberOf\".\n memberOf: string | null;\n };\n};\n\n/**\n * The settings that govern the reading and interpretation of groups.\n *\n * @public\n */\nexport type GroupConfig = {\n // The DN under which groups are stored.\n dn: string;\n // The search options to use.\n // Only the scope, filter, attributes, and paged fields are supported.\n options: SearchOptions;\n\n // JSON paths (on a.b.c form) and hard coded values to set on those paths\n set?: { [path: string]: JsonValue };\n // Mappings from well known entity fields, to LDAP attribute names\n map: {\n // The name of the attribute that holds the relative distinguished name of\n // each entry. Defaults to \"cn\".\n rdn: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.name field of the entity. Defaults to \"cn\".\n name: string;\n // The name of the attribute that shall be used for the value of the\n // metadata.description field of the entity. Defaults to \"description\".\n description: string;\n // The name of the attribute that shall be used for the value of the\n // spec.type field of the entity. Defaults to \"groupType\".\n type: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.displayName field of the entity. Defaults to \"cn\".\n displayName: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.email field of the entity.\n email?: string;\n // The name of the attribute that shall be used for the value of the\n // spec.profile.picture field of the entity.\n picture?: string;\n // The name of the attribute that shall be used for the values of the\n // spec.parent field of the entity. Defaults to \"memberOf\".\n memberOf: string | null;\n // The name of the attribute that shall be used for the values of the\n // spec.children field of the entity. Defaults to \"member\".\n members: string | null;\n };\n};\n\n/**\n * Configuration for LDAP vendor-specific attributes.\n *\n * Allows custom attribute names for distinguished names (DN) and\n * universally unique identifiers (UUID) in LDAP directories.\n *\n * @public\n */\nexport type VendorConfig = {\n /**\n * Attribute name for the distinguished name (DN) of an entry,\n */\n dnAttributeName?: string;\n\n /**\n * Attribute name for the unique identifier (UUID) of an entry,\n */\n uuidAttributeName?: string;\n};\n\nconst defaultUserConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'uid',\n name: 'uid',\n displayName: 'cn',\n email: 'mail',\n memberOf: 'memberOf',\n },\n};\n\nconst defaultGroupConfig = {\n options: {\n scope: 'one',\n attributes: ['*', '+'],\n },\n map: {\n rdn: 'cn',\n name: 'cn',\n description: 'description',\n displayName: 'cn',\n type: 'groupType',\n memberOf: 'memberOf',\n members: 'member',\n },\n};\n\nfunction freeze<T>(data: T): T {\n return JSON.parse(JSON.stringify(data), (_key, value) => {\n if (typeof value === 'object' && value !== null) {\n Object.freeze(value);\n }\n return value;\n });\n}\n\nfunction readTlsConfig(\n c: Config | undefined,\n): LdapProviderConfig['tls'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n rejectUnauthorized: c.getOptionalBoolean('rejectUnauthorized'),\n keys: c.getOptionalString('keys'),\n certs: c.getOptionalString('certs'),\n };\n}\n\nfunction readBindConfig(\n c: Config | undefined,\n): LdapProviderConfig['bind'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dn: c.getString('dn'),\n secret: c.getString('secret'),\n };\n}\n\nfunction readVendorConfig(\n c: Config | undefined,\n): LdapProviderConfig['vendor'] | undefined {\n if (!c) {\n return undefined;\n }\n return {\n dnAttributeName: c.getOptionalString('dnAttributeName'),\n uuidAttributeName: c.getOptionalString('uuidAttributeName'),\n };\n}\n\nfunction readOptionsConfig(c: Config | undefined): SearchOptions {\n if (!c) {\n return {};\n }\n\n const paged = readOptionsPagedConfig(c);\n\n return {\n scope: c.getOptionalString('scope') as SearchOptions['scope'],\n filter: formatFilter(c.getOptionalString('filter')),\n attributes: c.getOptionalStringArray('attributes'),\n sizeLimit: c.getOptionalNumber('sizeLimit'),\n timeLimit: c.getOptionalNumber('timeLimit'),\n derefAliases: c.getOptionalNumber(\n 'derefAliases',\n ) as SearchOptions['derefAliases'],\n returnAttributeValues: c.getOptionalBoolean('attributeValues'),\n ...(paged !== undefined ? { paged } : undefined),\n };\n}\n\nfunction readOptionsPagedConfig(c: Config): SearchOptions['paged'] {\n const pagedConfig = c.getOptional('paged');\n if (pagedConfig === undefined) {\n return undefined;\n }\n\n if (pagedConfig === true || pagedConfig === false) {\n return pagedConfig;\n }\n\n const pageSize = c.getOptionalNumber('paged.pageSize');\n const pagePause = c.getOptionalBoolean('paged.pagePause');\n return {\n ...(pageSize !== undefined ? { pageSize } : undefined),\n ...(pagePause !== undefined ? { pagePause } : undefined),\n };\n}\n\nfunction readSetConfig(\n c: Config | undefined,\n): { [path: string]: JsonValue } | undefined {\n if (!c) {\n return undefined;\n }\n return c.get();\n}\n\nfunction readUserMapConfig(c: Config | undefined): Partial<UserConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n };\n}\n\nfunction readGroupMapConfig(\n c: Config | undefined,\n): Partial<GroupConfig['map']> {\n if (!c) {\n return {};\n }\n\n return {\n rdn: c.getOptionalString('rdn'),\n name: c.getOptionalString('name'),\n description: c.getOptionalString('description'),\n type: c.getOptionalString('type'),\n displayName: c.getOptionalString('displayName'),\n email: c.getOptionalString('email'),\n picture: c.getOptionalString('picture'),\n memberOf: c.getOptionalString('memberOf'),\n members: c.getOptionalString('members'),\n };\n}\n\nfunction readUserConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['users']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleUserConfig(it));\n }\n return [readSingleUserConfig(c)];\n}\n\nfunction readSingleUserConfig(c: Config): RecursivePartial<UserConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readUserMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction readGroupConfig(\n c: Config | Config[] | undefined,\n): RecursivePartial<LdapProviderConfig['groups']> {\n if (!c) {\n return [];\n }\n if (Array.isArray(c)) {\n return c.map(it => readSingleGroupConfig(it));\n }\n return [readSingleGroupConfig(c)];\n}\n\nfunction readSingleGroupConfig(c: Config): RecursivePartial<GroupConfig> {\n return {\n dn: c.getString('dn'),\n options: readOptionsConfig(c.getOptionalConfig('options')),\n set: readSetConfig(c.getOptionalConfig('set')),\n map: readGroupMapConfig(c.getOptionalConfig('map')),\n };\n}\n\nfunction formatFilter(filter?: string): string | undefined {\n // Remove extra whitespace between blocks to support multiline filters from the configuration\n return filter?.replace(/\\s*(\\(|\\))/g, '$1')?.trim();\n}\n\n/**\n * Parses configuration.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n * @deprecated This exists for backwards compatibility only and will be removed in the future.\n */\nexport function readLdapLegacyConfig(config: Config): LdapProviderConfig[] {\n const providerConfigs = config.getOptionalConfigArray('providers') ?? [];\n return providerConfigs.map(c => {\n const newConfig = {\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(c.getConfig('users')).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(c.getConfig('groups')).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\n/**\n * Parses all configured providers.\n *\n * @param config - The root of the LDAP config hierarchy\n *\n * @public\n */\nexport function readProviderConfigs(config: Config): LdapProviderConfig[] {\n const providersConfig = config.getOptionalConfig('catalog.providers.ldapOrg');\n if (!providersConfig) {\n return [];\n }\n\n return providersConfig.keys().map(id => {\n const c = providersConfig.getConfig(id);\n const schedule = c.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n c.getConfig('schedule'),\n )\n : undefined;\n\n const isUserList = Array.isArray(c.getOptional('users'));\n const isGroupList = Array.isArray(c.getOptional('groups'));\n\n const newConfig = {\n id,\n target: trimEnd(c.getString('target'), '/'),\n tls: readTlsConfig(c.getOptionalConfig('tls')),\n bind: readBindConfig(c.getOptionalConfig('bind')),\n users: readUserConfig(\n isUserList\n ? c.getOptionalConfigArray('users')\n : c.getOptionalConfig('users'),\n ).map(it => {\n return mergeWith({}, defaultUserConfig, it, replaceArraysIfPresent);\n }),\n groups: readGroupConfig(\n isGroupList\n ? c.getOptionalConfigArray('groups')\n : c.getOptionalConfig('groups'),\n ).map(it => {\n return mergeWith({}, defaultGroupConfig, it, replaceArraysIfPresent);\n }),\n schedule,\n vendor: readVendorConfig(c.getOptionalConfig('vendor')),\n };\n\n return freeze(newConfig) as LdapProviderConfig;\n });\n}\n\nfunction replaceArraysIfPresent(_into: any, from: any) {\n // Replace arrays instead of merging, otherwise default behavior\n return Array.isArray(from) ? from : undefined;\n}\n"],"names":["trimEnd","mergeWith","readSchedulerServiceTaskScheduleDefinitionFromConfig"],"mappings":"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"}
|
package/dist/ldap/index.cjs.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
var vendors$1 = require('./vendors.cjs.js');
|
|
4
4
|
require('@backstage/errors');
|
|
5
5
|
require('fs/promises');
|
|
6
|
-
require('
|
|
7
|
-
require('lodash');
|
|
6
|
+
require('ldapts');
|
|
8
7
|
require('tls');
|
|
9
8
|
require('@backstage/backend-plugin-api');
|
|
10
9
|
require('lodash/mergeWith');
|
|
10
|
+
require('lodash');
|
|
11
11
|
require('@backstage/catalog-model');
|
|
12
12
|
require('lodash/set');
|
|
13
13
|
require('lodash/cloneDeep');
|
package/dist/ldap/read.cjs.js
CHANGED
|
@@ -78,16 +78,17 @@ async function readLdapUsers(client, userConfig, vendorConfig, opts) {
|
|
|
78
78
|
const transformer = opts?.transformer ?? defaultUserTransformer;
|
|
79
79
|
for (const cfg of userConfig) {
|
|
80
80
|
const { dn, options, map } = cfg;
|
|
81
|
-
await client.
|
|
82
|
-
|
|
81
|
+
const searchResult = await client.search(dn, options);
|
|
82
|
+
for (const entry of searchResult.searchEntries) {
|
|
83
|
+
const entity = await transformer(vendor, cfg, entry);
|
|
83
84
|
if (!entity) {
|
|
84
|
-
|
|
85
|
+
continue;
|
|
85
86
|
}
|
|
86
|
-
mapReferencesAttr(
|
|
87
|
+
mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {
|
|
87
88
|
ensureItems(userMemberOf, myDn, vs);
|
|
88
89
|
});
|
|
89
90
|
entities.push(entity);
|
|
90
|
-
}
|
|
91
|
+
}
|
|
91
92
|
}
|
|
92
93
|
return { users: entities, userMemberOf };
|
|
93
94
|
}
|
|
@@ -161,13 +162,11 @@ async function readLdapGroups(client, groupConfig, vendorConfig, opts) {
|
|
|
161
162
|
const transformer = opts?.transformer ?? defaultGroupTransformer;
|
|
162
163
|
for (const cfg of groupConfig) {
|
|
163
164
|
const { dn, map, options } = cfg;
|
|
164
|
-
await client.
|
|
165
|
-
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
165
|
+
const searchResult = await client.search(dn, options);
|
|
166
|
+
for (const entry of searchResult.searchEntries) {
|
|
168
167
|
const entity = await transformer(vendor, cfg, entry);
|
|
169
168
|
if (!entity) {
|
|
170
|
-
|
|
169
|
+
continue;
|
|
171
170
|
}
|
|
172
171
|
mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {
|
|
173
172
|
ensureItems(groupMemberOf, myDn, vs);
|
|
@@ -176,7 +175,7 @@ async function readLdapGroups(client, groupConfig, vendorConfig, opts) {
|
|
|
176
175
|
ensureItems(groupMember, myDn, vs);
|
|
177
176
|
});
|
|
178
177
|
groups.push(entity);
|
|
179
|
-
}
|
|
178
|
+
}
|
|
180
179
|
}
|
|
181
180
|
return {
|
|
182
181
|
groups,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.cjs.js","sources":["../../src/ldap/read.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { SearchEntry } from 'ldapjs';\nimport lodashSet from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport { buildOrgHierarchy } from './org';\nimport { LdapClient } from './client';\nimport { GroupConfig, UserConfig, VendorConfig } from './config';\nimport {\n LDAP_DN_ANNOTATION,\n LDAP_RDN_ANNOTATION,\n LDAP_UUID_ANNOTATION,\n} from './constants';\nimport { LdapVendor } from './vendors';\nimport { GroupTransformer, UserTransformer } from './types';\nimport { mapStringAttr } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n vendor: LdapVendor,\n config: UserConfig,\n entry: SearchEntry,\n): Promise<UserEntity | undefined> {\n const { set, map } = config;\n\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'User',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n profile: {},\n memberOf: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n\n if (!entity.metadata.name) {\n throw new InputError(\n `User syncing failed: missing '${map.name}' attribute, consider applying a user filter to skip processing users with incomplete data.`,\n );\n }\n\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads users out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The user data configuration\n * @param opts - Additional options\n */\nexport async function readLdapUsers(\n client: LdapClient,\n userConfig: UserConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: { transformer?: UserTransformer },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n userMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n}> {\n if (userConfig.length === 0) {\n return { users: [], userMemberOf: new Map() };\n }\n const entities: UserEntity[] = [];\n const userMemberOf: Map<string, Set<string>> = new Map();\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n const transformer = opts?.transformer ?? defaultUserTransformer;\n\n for (const cfg of userConfig) {\n const { dn, options, map } = cfg;\n await client.searchStreaming(dn, options, async user => {\n const entity = await transformer(vendor, cfg, user);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(user, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(userMemberOf, myDn, vs);\n });\n\n entities.push(entity);\n });\n }\n\n return { users: entities, userMemberOf };\n}\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n vendor: LdapVendor,\n config: GroupConfig,\n entry: SearchEntry,\n): Promise<GroupEntity | undefined> {\n const { set, map } = config;\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'Group',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n type: 'unknown',\n profile: {},\n children: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n\n if (!entity.metadata.name) {\n throw new InputError(\n `Group syncing failed: missing '${map.name}' attribute, consider applying a group filter to skip processing groups with incomplete data.`,\n );\n }\n\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.type, v => {\n entity.spec.type = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The group data configuration\n * @param opts - Additional options\n */\nexport async function readLdapGroups(\n client: LdapClient,\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: {\n transformer?: GroupTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n groupMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n groupMember: Map<string, Set<string>>; // DN -> DN or UUID of groups & users\n}> {\n if (groupConfig.length === 0) {\n return { groups: [], groupMemberOf: new Map(), groupMember: new Map() };\n }\n const groups: GroupEntity[] = [];\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const groupMember: Map<string, Set<string>> = new Map();\n\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n\n const transformer = opts?.transformer ?? defaultGroupTransformer;\n\n for (const cfg of groupConfig) {\n const { dn, map, options } = cfg;\n\n await client.searchStreaming(dn, options, async entry => {\n if (!entry) {\n return;\n }\n\n const entity = await transformer(vendor, cfg, entry);\n\n if (!entity) {\n return;\n }\n\n mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(groupMemberOf, myDn, vs);\n });\n\n mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => {\n ensureItems(groupMember, myDn, vs);\n });\n\n groups.push(entity);\n });\n }\n\n return {\n groups,\n groupMemberOf,\n groupMember,\n };\n}\n\n/**\n * Reads users and groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param userConfig - The user data configuration\n * @param groupConfig - The group data configuration\n * @param options - Additional options\n *\n * @public\n */\nexport async function readLdapOrg(\n client: LdapClient,\n userConfig: UserConfig[],\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n options: {\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[];\n groups: GroupEntity[];\n}> {\n // Invokes the above \"raw\" read functions and stitches together the results\n // with all relations etc filled in.\n\n const { users, userMemberOf } = await readLdapUsers(\n client,\n userConfig,\n vendorConfig,\n {\n transformer: options?.userTransformer,\n },\n );\n const { groups, groupMemberOf, groupMember } = await readLdapGroups(\n client,\n groupConfig,\n vendorConfig,\n { transformer: options?.groupTransformer },\n );\n\n resolveRelations(groups, users, userMemberOf, groupMemberOf, groupMember);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\n//\n// Helpers\n//\n\n// Maps a multi-valued attribute of references to other objects, to a consumer\nfunction mapReferencesAttr(\n entry: SearchEntry,\n vendor: LdapVendor,\n attributeName: string | undefined | null,\n setter: (sourceDn: string, targets: string[]) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n const dn = vendor.decodeStringAttribute(entry, vendor.dnAttributeName);\n if (values && dn && dn.length === 1) {\n setter(dn[0], values);\n }\n }\n}\n\n// Inserts a number of values in a key-values mapping\nfunction ensureItems(\n target: Map<string, Set<string>>,\n key: string,\n values: string[],\n) {\n if (key) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n for (const value of values) {\n if (value) {\n set!.add(value);\n }\n }\n }\n}\n\n/**\n * Helper function which dual searches the user/group maps first for original value, then for lowercased value.\n * @param map - The map of DN's user or group as the key usually multicased.\n * @param searchValue - The DN/memberOf search criteria which could potentially not match the map DN by case.\n * @returns The value/result of the search criteria dual searching.\n */\nfunction getValueFromMapWithInsensitiveKey(\n map: Map<string, any>,\n searchValue: string,\n) {\n const result = map.get(searchValue);\n return result ? result : map.get(searchValue.toLocaleLowerCase('en-US'));\n}\n\n/**\n * Takes groups and entities with empty relations, and fills in the various\n * relations that were returned by the readers, and forms the org hierarchy.\n *\n * @param groups - Group entities with empty relations; modified in place\n * @param users - User entities with empty relations; modified in place\n * @param userMemberOf - For a user DN, the set of group DNs or UUIDs that the\n * user is a member of\n * @param groupMemberOf - For a group DN, the set of group DNs or UUIDs that\n * the group is a member of (parents in the hierarchy)\n * @param groupMember - For a group DN, the set of group DNs or UUIDs that are\n * members of the group (children in the hierarchy)\n */\nexport function resolveRelations(\n groups: GroupEntity[],\n users: UserEntity[],\n userMemberOf: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n groupMember: Map<string, Set<string>>,\n) {\n // Build reference lookup tables - all of the relations that are output from\n // the above calls can be expressed as either DNs or UUIDs so we need to be\n // able to find by both, as well as the entity reference. Note that we expect them to not\n // collide here - this is a reasonable assumption as long as the fields are\n // the supported forms.\n const userMap: Map<string, UserEntity> = new Map(); // by entityRef, dn, uuid\n const groupMap: Map<string, GroupEntity> = new Map(); // by entityRef, dn, uuid\n for (const user of users) {\n userMap.set(stringifyEntityRef(user), user);\n userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user);\n userMap.set(\n user.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase(\n 'en-US',\n ),\n user,\n );\n userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user);\n }\n for (const group of groups) {\n groupMap.set(stringifyEntityRef(group), group);\n groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group);\n groupMap.set(\n group.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase(\n 'en-US',\n ),\n group,\n );\n groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group);\n }\n\n // This can happen e.g. if entryUUID wasn't returned by the server\n userMap.delete('');\n groupMap.delete('');\n userMap.delete(undefined!);\n groupMap.delete(undefined!);\n\n // Fill in all of the immediate relations, now keyed on the entity reference. We\n // keep all parents at this point, whether the target model can support more\n // than one or not (it gets filtered farther down). And group children are\n // only groups in here.\n const newUserMemberOf: Map<string, Set<string>> = new Map();\n const newGroupParents: Map<string, Set<string>> = new Map();\n const newGroupChildren: Map<string, Set<string>> = new Map();\n\n // Resolve and store in the intermediaries. It may seem redundant that the\n // input data has both parent and children directions, as well as both\n // user->group and group->user - the reason is that different LDAP schemas\n // express relations in different directions. Some may have a user memberOf\n // overlay, some don't, for example.\n for (const [userN, groupsN] of userMemberOf.entries()) {\n const user = getValueFromMapWithInsensitiveKey(userMap, userN);\n if (user) {\n for (const groupN of groupsN) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n ensureItems(newUserMemberOf, stringifyEntityRef(user), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, parentsN] of groupMemberOf.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n for (const parentN of parentsN) {\n const parentGroup = getValueFromMapWithInsensitiveKey(\n groupMap,\n parentN,\n );\n if (parentGroup) {\n ensureItems(newGroupParents, stringifyEntityRef(group), [\n stringifyEntityRef(parentGroup),\n ]);\n ensureItems(newGroupChildren, stringifyEntityRef(parentGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, membersN] of groupMember.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n for (const memberN of membersN) {\n // Group members can be both users and groups in the input model, so\n // try both\n const memberUser = getValueFromMapWithInsensitiveKey(userMap, memberN);\n if (memberUser) {\n ensureItems(newUserMemberOf, stringifyEntityRef(memberUser), [\n stringifyEntityRef(group),\n ]);\n } else {\n const memberGroup = getValueFromMapWithInsensitiveKey(\n groupMap,\n memberN,\n );\n if (memberGroup) {\n ensureItems(newGroupChildren, stringifyEntityRef(group), [\n stringifyEntityRef(memberGroup),\n ]);\n ensureItems(newGroupParents, stringifyEntityRef(memberGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n }\n\n // Write down the relations again into the actual entities\n for (const [userN, groupsN] of newUserMemberOf.entries()) {\n const user = getValueFromMapWithInsensitiveKey(userMap, userN);\n if (user) {\n user.spec.memberOf = Array.from(groupsN).sort();\n }\n }\n for (const [groupN, parentsN] of newGroupParents.entries()) {\n if (parentsN.size === 1) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n group.spec.parent = parentsN.values().next().value;\n }\n }\n }\n for (const [groupN, childrenN] of newGroupChildren.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n group.spec.children = Array.from(childrenN).sort();\n }\n }\n\n // Fill out the rest of the hierarchy\n buildOrgHierarchy(groups);\n}\n"],"names":["lodashSet","cloneDeep","mapStringAttr","InputError","LDAP_RDN_ANNOTATION","LDAP_UUID_ANNOTATION","LDAP_DN_ANNOTATION","stringifyEntityRef","buildOrgHierarchy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"read.cjs.js","sources":["../../src/ldap/read.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n GroupEntity,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Entry } from 'ldapts';\nimport lodashSet from 'lodash/set';\nimport cloneDeep from 'lodash/cloneDeep';\nimport { buildOrgHierarchy } from './org';\nimport { LdapClient } from './client';\nimport { GroupConfig, UserConfig, VendorConfig } from './config';\nimport {\n LDAP_DN_ANNOTATION,\n LDAP_RDN_ANNOTATION,\n LDAP_UUID_ANNOTATION,\n} from './constants';\nimport { LdapVendor } from './vendors';\nimport { GroupTransformer, UserTransformer } from './types';\nimport { mapStringAttr } from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { InputError } from '@backstage/errors';\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * User entity.\n *\n * @public\n */\nexport async function defaultUserTransformer(\n vendor: LdapVendor,\n config: UserConfig,\n entry: Entry,\n): Promise<UserEntity | undefined> {\n const { set, map } = config;\n\n const entity: UserEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'User',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n profile: {},\n memberOf: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n\n if (!entity.metadata.name) {\n throw new InputError(\n `User syncing failed: missing '${map.name}' attribute, consider applying a user filter to skip processing users with incomplete data.`,\n );\n }\n\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads users out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The user data configuration\n * @param opts - Additional options\n */\nexport async function readLdapUsers(\n client: LdapClient,\n userConfig: UserConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: { transformer?: UserTransformer },\n): Promise<{\n users: UserEntity[]; // With all relations empty\n userMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n}> {\n if (userConfig.length === 0) {\n return { users: [], userMemberOf: new Map() };\n }\n const entities: UserEntity[] = [];\n const userMemberOf: Map<string, Set<string>> = new Map();\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n const transformer = opts?.transformer ?? defaultUserTransformer;\n\n for (const cfg of userConfig) {\n const { dn, options, map } = cfg;\n const searchResult = await client.search(dn, options);\n for (const entry of searchResult.searchEntries) {\n const entity = await transformer(vendor, cfg, entry);\n\n if (!entity) {\n continue;\n }\n\n mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(userMemberOf, myDn, vs);\n });\n\n entities.push(entity);\n }\n }\n\n return { users: entities, userMemberOf };\n}\n\n/**\n * The default implementation of the transformation from an LDAP entry to a\n * Group entity.\n *\n * @public\n */\nexport async function defaultGroupTransformer(\n vendor: LdapVendor,\n config: GroupConfig,\n entry: Entry,\n): Promise<GroupEntity | undefined> {\n const { set, map } = config;\n const entity: GroupEntity = {\n apiVersion: 'backstage.io/v1beta1',\n kind: 'Group',\n metadata: {\n name: '',\n annotations: {},\n },\n spec: {\n type: 'unknown',\n profile: {},\n children: [],\n },\n };\n\n if (set) {\n for (const [path, value] of Object.entries(set)) {\n lodashSet(entity, path, cloneDeep(value));\n }\n }\n\n mapStringAttr(entry, vendor, map.name, v => {\n entity.metadata.name = v;\n });\n\n if (!entity.metadata.name) {\n throw new InputError(\n `Group syncing failed: missing '${map.name}' attribute, consider applying a group filter to skip processing groups with incomplete data.`,\n );\n }\n\n mapStringAttr(entry, vendor, map.description, v => {\n entity.metadata.description = v;\n });\n mapStringAttr(entry, vendor, map.rdn, v => {\n entity.metadata.annotations![LDAP_RDN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.uuidAttributeName, v => {\n entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, vendor.dnAttributeName, v => {\n entity.metadata.annotations![LDAP_DN_ANNOTATION] = v;\n });\n mapStringAttr(entry, vendor, map.type, v => {\n entity.spec.type = v;\n });\n mapStringAttr(entry, vendor, map.displayName, v => {\n entity.spec.profile!.displayName = v;\n });\n mapStringAttr(entry, vendor, map.email, v => {\n entity.spec.profile!.email = v;\n });\n mapStringAttr(entry, vendor, map.picture, v => {\n entity.spec.profile!.picture = v;\n });\n\n return entity;\n}\n\n/**\n * Reads groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param config - The group data configuration\n * @param opts - Additional options\n */\nexport async function readLdapGroups(\n client: LdapClient,\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n opts?: {\n transformer?: GroupTransformer;\n },\n): Promise<{\n groups: GroupEntity[]; // With all relations empty\n groupMemberOf: Map<string, Set<string>>; // DN -> DN or UUID of groups\n groupMember: Map<string, Set<string>>; // DN -> DN or UUID of groups & users\n}> {\n if (groupConfig.length === 0) {\n return { groups: [], groupMemberOf: new Map(), groupMember: new Map() };\n }\n const groups: GroupEntity[] = [];\n const groupMemberOf: Map<string, Set<string>> = new Map();\n const groupMember: Map<string, Set<string>> = new Map();\n\n const vendorDefaults = await client.getVendor();\n const vendor: LdapVendor = {\n dnAttributeName:\n vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName,\n uuidAttributeName:\n vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName,\n decodeStringAttribute: vendorDefaults.decodeStringAttribute,\n };\n\n const transformer = opts?.transformer ?? defaultGroupTransformer;\n\n for (const cfg of groupConfig) {\n const { dn, map, options } = cfg;\n const searchResult = await client.search(dn, options);\n for (const entry of searchResult.searchEntries) {\n const entity = await transformer(vendor, cfg, entry);\n\n if (!entity) {\n continue;\n }\n\n mapReferencesAttr(entry, vendor, map.memberOf, (myDn, vs) => {\n ensureItems(groupMemberOf, myDn, vs);\n });\n\n mapReferencesAttr(entry, vendor, map.members, (myDn, vs) => {\n ensureItems(groupMember, myDn, vs);\n });\n\n groups.push(entity);\n }\n }\n\n return {\n groups,\n groupMemberOf,\n groupMember,\n };\n}\n\n/**\n * Reads users and groups out of an LDAP provider.\n *\n * @param client - The LDAP client\n * @param userConfig - The user data configuration\n * @param groupConfig - The group data configuration\n * @param options - Additional options\n *\n * @public\n */\nexport async function readLdapOrg(\n client: LdapClient,\n userConfig: UserConfig[],\n groupConfig: GroupConfig[],\n vendorConfig: VendorConfig | undefined,\n options: {\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n logger: LoggerService;\n },\n): Promise<{\n users: UserEntity[];\n groups: GroupEntity[];\n}> {\n // Invokes the above \"raw\" read functions and stitches together the results\n // with all relations etc filled in.\n\n const { users, userMemberOf } = await readLdapUsers(\n client,\n userConfig,\n vendorConfig,\n {\n transformer: options?.userTransformer,\n },\n );\n const { groups, groupMemberOf, groupMember } = await readLdapGroups(\n client,\n groupConfig,\n vendorConfig,\n { transformer: options?.groupTransformer },\n );\n\n resolveRelations(groups, users, userMemberOf, groupMemberOf, groupMember);\n users.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n groups.sort((a, b) => a.metadata.name.localeCompare(b.metadata.name));\n\n return { users, groups };\n}\n\n//\n// Helpers\n//\n\n// Maps a multi-valued attribute of references to other objects, to a consumer\nfunction mapReferencesAttr(\n entry: Entry,\n vendor: LdapVendor,\n attributeName: string | undefined | null,\n setter: (sourceDn: string, targets: string[]) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n const dn = vendor.decodeStringAttribute(entry, vendor.dnAttributeName);\n if (values && dn && dn.length === 1) {\n setter(dn[0], values);\n }\n }\n}\n\n// Inserts a number of values in a key-values mapping\nfunction ensureItems(\n target: Map<string, Set<string>>,\n key: string,\n values: string[],\n) {\n if (key) {\n let set = target.get(key);\n if (!set) {\n set = new Set();\n target.set(key, set);\n }\n for (const value of values) {\n if (value) {\n set!.add(value);\n }\n }\n }\n}\n\n/**\n * Helper function which dual searches the user/group maps first for original value, then for lowercased value.\n * @param map - The map of DN's user or group as the key usually multicased.\n * @param searchValue - The DN/memberOf search criteria which could potentially not match the map DN by case.\n * @returns The value/result of the search criteria dual searching.\n */\nfunction getValueFromMapWithInsensitiveKey(\n map: Map<string, any>,\n searchValue: string,\n) {\n const result = map.get(searchValue);\n return result ? result : map.get(searchValue.toLocaleLowerCase('en-US'));\n}\n\n/**\n * Takes groups and entities with empty relations, and fills in the various\n * relations that were returned by the readers, and forms the org hierarchy.\n *\n * @param groups - Group entities with empty relations; modified in place\n * @param users - User entities with empty relations; modified in place\n * @param userMemberOf - For a user DN, the set of group DNs or UUIDs that the\n * user is a member of\n * @param groupMemberOf - For a group DN, the set of group DNs or UUIDs that\n * the group is a member of (parents in the hierarchy)\n * @param groupMember - For a group DN, the set of group DNs or UUIDs that are\n * members of the group (children in the hierarchy)\n */\nexport function resolveRelations(\n groups: GroupEntity[],\n users: UserEntity[],\n userMemberOf: Map<string, Set<string>>,\n groupMemberOf: Map<string, Set<string>>,\n groupMember: Map<string, Set<string>>,\n) {\n // Build reference lookup tables - all of the relations that are output from\n // the above calls can be expressed as either DNs or UUIDs so we need to be\n // able to find by both, as well as the entity reference. Note that we expect them to not\n // collide here - this is a reasonable assumption as long as the fields are\n // the supported forms.\n const userMap: Map<string, UserEntity> = new Map(); // by entityRef, dn, uuid\n const groupMap: Map<string, GroupEntity> = new Map(); // by entityRef, dn, uuid\n for (const user of users) {\n userMap.set(stringifyEntityRef(user), user);\n userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user);\n userMap.set(\n user.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase(\n 'en-US',\n ),\n user,\n );\n userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user);\n userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user);\n }\n for (const group of groups) {\n groupMap.set(stringifyEntityRef(group), group);\n groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group);\n groupMap.set(\n group.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase(\n 'en-US',\n ),\n group,\n );\n groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group);\n groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group);\n }\n\n // This can happen e.g. if entryUUID wasn't returned by the server\n userMap.delete('');\n groupMap.delete('');\n userMap.delete(undefined!);\n groupMap.delete(undefined!);\n\n // Fill in all of the immediate relations, now keyed on the entity reference. We\n // keep all parents at this point, whether the target model can support more\n // than one or not (it gets filtered farther down). And group children are\n // only groups in here.\n const newUserMemberOf: Map<string, Set<string>> = new Map();\n const newGroupParents: Map<string, Set<string>> = new Map();\n const newGroupChildren: Map<string, Set<string>> = new Map();\n\n // Resolve and store in the intermediaries. It may seem redundant that the\n // input data has both parent and children directions, as well as both\n // user->group and group->user - the reason is that different LDAP schemas\n // express relations in different directions. Some may have a user memberOf\n // overlay, some don't, for example.\n for (const [userN, groupsN] of userMemberOf.entries()) {\n const user = getValueFromMapWithInsensitiveKey(userMap, userN);\n if (user) {\n for (const groupN of groupsN) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n ensureItems(newUserMemberOf, stringifyEntityRef(user), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, parentsN] of groupMemberOf.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n for (const parentN of parentsN) {\n const parentGroup = getValueFromMapWithInsensitiveKey(\n groupMap,\n parentN,\n );\n if (parentGroup) {\n ensureItems(newGroupParents, stringifyEntityRef(group), [\n stringifyEntityRef(parentGroup),\n ]);\n ensureItems(newGroupChildren, stringifyEntityRef(parentGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n for (const [groupN, membersN] of groupMember.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n for (const memberN of membersN) {\n // Group members can be both users and groups in the input model, so\n // try both\n const memberUser = getValueFromMapWithInsensitiveKey(userMap, memberN);\n if (memberUser) {\n ensureItems(newUserMemberOf, stringifyEntityRef(memberUser), [\n stringifyEntityRef(group),\n ]);\n } else {\n const memberGroup = getValueFromMapWithInsensitiveKey(\n groupMap,\n memberN,\n );\n if (memberGroup) {\n ensureItems(newGroupChildren, stringifyEntityRef(group), [\n stringifyEntityRef(memberGroup),\n ]);\n ensureItems(newGroupParents, stringifyEntityRef(memberGroup), [\n stringifyEntityRef(group),\n ]);\n }\n }\n }\n }\n }\n\n // Write down the relations again into the actual entities\n for (const [userN, groupsN] of newUserMemberOf.entries()) {\n const user = getValueFromMapWithInsensitiveKey(userMap, userN);\n if (user) {\n user.spec.memberOf = Array.from(groupsN).sort();\n }\n }\n for (const [groupN, parentsN] of newGroupParents.entries()) {\n if (parentsN.size === 1) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n group.spec.parent = parentsN.values().next().value;\n }\n }\n }\n for (const [groupN, childrenN] of newGroupChildren.entries()) {\n const group = getValueFromMapWithInsensitiveKey(groupMap, groupN);\n if (group) {\n group.spec.children = Array.from(childrenN).sort();\n }\n }\n\n // Fill out the rest of the hierarchy\n buildOrgHierarchy(groups);\n}\n"],"names":["lodashSet","cloneDeep","mapStringAttr","InputError","LDAP_RDN_ANNOTATION","LDAP_UUID_ANNOTATION","LDAP_DN_ANNOTATION","stringifyEntityRef","buildOrgHierarchy"],"mappings":"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"}
|
package/dist/ldap/util.cjs.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var lodash = require('lodash');
|
|
4
|
-
|
|
5
|
-
function errorString(error) {
|
|
6
|
-
return `${error.code} ${error.name}: ${error.message}`;
|
|
7
|
-
}
|
|
8
3
|
function mapStringAttr(entry, vendor, attributeName, setter) {
|
|
9
4
|
if (attributeName) {
|
|
10
5
|
const values = vendor.decodeStringAttribute(entry, attributeName);
|
|
@@ -13,17 +8,6 @@ function mapStringAttr(entry, vendor, attributeName, setter) {
|
|
|
13
8
|
}
|
|
14
9
|
}
|
|
15
10
|
}
|
|
16
|
-
function createOptions(inputOptions) {
|
|
17
|
-
const result = lodash.cloneDeep(inputOptions);
|
|
18
|
-
if (result.paged === true) {
|
|
19
|
-
result.paged = { pagePause: true };
|
|
20
|
-
} else if (typeof result.paged === "object") {
|
|
21
|
-
result.paged.pagePause = true;
|
|
22
|
-
}
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
11
|
|
|
26
|
-
exports.createOptions = createOptions;
|
|
27
|
-
exports.errorString = errorString;
|
|
28
12
|
exports.mapStringAttr = mapStringAttr;
|
|
29
13
|
//# sourceMappingURL=util.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../src/ldap/util.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../src/ldap/util.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entry } from 'ldapts';\nimport { LdapVendor } from './vendors';\n\n/**\n * Maps a single-valued attribute to a consumer.\n *\n * This helper can be useful when implementing a user or group transformer.\n *\n * @param entry - The LDAP source entry\n * @param vendor - The LDAP vendor\n * @param attributeName - The source attribute to map. If the attribute is\n * undefined the mapping will be silently ignored.\n * @param setter - The function to be called with the decoded attribute from the\n * source entry\n *\n * @public\n */\nexport function mapStringAttr(\n entry: Entry,\n vendor: LdapVendor,\n attributeName: string | undefined,\n setter: (value: string) => void,\n) {\n if (attributeName) {\n const values = vendor.decodeStringAttribute(entry, attributeName);\n if (values && values.length === 1) {\n setter(values[0]);\n }\n }\n}\n\nexport type RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends (infer U)[]\n ? RecursivePartial<U>[]\n : T[P] extends object\n ? RecursivePartial<T[P]>\n : T[P];\n};\n"],"names":[],"mappings":";;AAiCO,SAAS,aAAA,CACd,KAAA,EACA,MAAA,EACA,aAAA,EACA,MAAA,EACA;AACA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,qBAAA,CAAsB,KAAA,EAAO,aAAa,CAAA;AAChE,IAAA,IAAI,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG;AACjC,MAAA,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IAClB;AAAA,EACF;AACF;;;;"}
|
package/dist/ldap/vendors.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vendors.cjs.js","sources":["../../src/ldap/vendors.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"vendors.cjs.js","sources":["../../src/ldap/vendors.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entry } from 'ldapts';\n\n/**\n * An LDAP Vendor handles unique nuances between different vendors.\n *\n * @public\n */\nexport type LdapVendor = {\n /**\n * The attribute name that holds the distinguished name (DN) for an entry.\n */\n dnAttributeName: string;\n /**\n * The attribute name that holds a universal unique identifier for an entry.\n */\n uuidAttributeName: string;\n\n /**\n * Decode ldap entry values for a given attribute name to their string representation.\n *\n * @param entry - The ldap entry\n * @param name - The attribute to decode\n */\n decodeStringAttribute: (entry: Entry, name: string) => string[];\n};\n\nexport const DefaultLdapVendor: LdapVendor = {\n dnAttributeName: 'entryDN',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const ActiveDirectoryVendor: LdapVendor = {\n dnAttributeName: 'distinguishedName',\n uuidAttributeName: 'objectGUID',\n decodeStringAttribute: (entry, name) => {\n const decoder = (value: string | Buffer) => {\n if (name === ActiveDirectoryVendor.uuidAttributeName) {\n return formatGUID(value);\n }\n return value.toString();\n };\n return decode(entry, name, decoder);\n },\n};\n\nexport const FreeIpaVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'ipaUniqueID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const AEDirVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'entryUUID',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const GoogleLdapVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'uid',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name, value => {\n return value.toString();\n });\n },\n};\n\nexport const LLDAPVendor: LdapVendor = {\n dnAttributeName: 'dn',\n uuidAttributeName: 'entryuuid',\n decodeStringAttribute: (entry, name) => {\n return decode(entry, name.toLocaleLowerCase('en-US'), value => {\n return value.toString();\n });\n },\n};\n\n// Decode an attribute to a consumer\nfunction decode(\n entry: Entry,\n attributeName: string,\n decoder: (value: string | Buffer) => string,\n): string[] {\n const values = entry[attributeName];\n if (Array.isArray(values)) {\n return values.map(v => {\n return decoder(v);\n });\n } else if (values) {\n return [decoder(values)];\n }\n return [];\n}\n\n// Formats a Microsoft Active Directory binary-encoded uuid to a readable string\n// See https://github.com/ldapjs/node-ldapjs/issues/297#issuecomment-137765214\nfunction formatGUID(objectGUID: string | Buffer): string {\n let data: Buffer;\n if (typeof objectGUID === 'string') {\n data = Buffer.from(objectGUID, 'binary');\n } else {\n data = objectGUID;\n }\n // GUID_FORMAT_D\n let template = '{3}{2}{1}{0}-{5}{4}-{7}{6}-{8}{9}-{10}{11}{12}{13}{14}{15}';\n\n // check each byte\n for (let i = 0; i < data.length; i++) {\n let dataStr = data[i].toString(16);\n dataStr = data[i] >= 16 ? dataStr : `0${dataStr}`;\n\n // insert that character into the template\n template = template.replace(`{${i}}`, dataStr);\n }\n return template;\n}\n"],"names":[],"mappings":"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"}
|
package/dist/module.cjs.js
CHANGED
|
@@ -5,10 +5,10 @@ var alpha = require('@backstage/plugin-catalog-node/alpha');
|
|
|
5
5
|
var LdapOrgEntityProvider = require('./processors/LdapOrgEntityProvider.cjs.js');
|
|
6
6
|
require('@backstage/errors');
|
|
7
7
|
require('fs/promises');
|
|
8
|
-
require('
|
|
9
|
-
require('lodash');
|
|
8
|
+
require('ldapts');
|
|
10
9
|
require('tls');
|
|
11
10
|
require('lodash/mergeWith');
|
|
11
|
+
require('lodash');
|
|
12
12
|
require('@backstage/catalog-model');
|
|
13
13
|
require('lodash/set');
|
|
14
14
|
require('lodash/cloneDeep');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LdapOrgReaderProcessor.cjs.js","sources":["../../src/processors/LdapOrgReaderProcessor.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n readLdapLegacyConfig,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts teams and users out of an LDAP server.\n *\n * @public\n */\nexport class LdapOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: LdapProviderConfig[];\n private readonly logger: LoggerService;\n private readonly groupTransformer?: GroupTransformer;\n private readonly userTransformer?: UserTransformer;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n },\n ) {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n return new LdapOrgReaderProcessor({\n ...options,\n providers: config ? readLdapLegacyConfig(config) : [],\n });\n }\n\n constructor(options: {\n providers: LdapProviderConfig[];\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n }) {\n this.providers = options.providers;\n this.logger = options.logger;\n this.groupTransformer = options.groupTransformer;\n this.userTransformer = options.userTransformer;\n }\n\n getProcessorName(): string {\n return 'LdapOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'ldap-org') {\n return false;\n }\n\n const provider = this.providers.find(p => location.target === p.target);\n if (!provider) {\n throw new Error(\n `There is no LDAP configuration that matches \"${location.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n // Read out all of the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading LDAP users and groups');\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.logger,\n provider.target,\n provider.bind,\n provider.tls,\n );\n const { users, groups } = await readLdapOrg(\n client,\n provider.users,\n provider.groups,\n provider.vendor,\n {\n groupTransformer: this.groupTransformer,\n userTransformer: this.userTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} LDAP users and ${groups.length} LDAP groups in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n"],"names":["config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","processingResult"],"mappings":"
|
|
1
|
+
{"version":3,"file":"LdapOrgReaderProcessor.cjs.js","sources":["../../src/processors/LdapOrgReaderProcessor.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n GroupTransformer,\n LdapClient,\n LdapProviderConfig,\n readLdapLegacyConfig,\n readLdapOrg,\n UserTransformer,\n} from '../ldap';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts teams and users out of an LDAP server.\n *\n * @public\n */\nexport class LdapOrgReaderProcessor implements CatalogProcessor {\n private readonly providers: LdapProviderConfig[];\n private readonly logger: LoggerService;\n private readonly groupTransformer?: GroupTransformer;\n private readonly userTransformer?: UserTransformer;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n },\n ) {\n // TODO(freben): Deprecate the old catalog.processors.ldapOrg config\n const config =\n configRoot.getOptionalConfig('ldap') ||\n configRoot.getOptionalConfig('catalog.processors.ldapOrg');\n return new LdapOrgReaderProcessor({\n ...options,\n providers: config ? readLdapLegacyConfig(config) : [],\n });\n }\n\n constructor(options: {\n providers: LdapProviderConfig[];\n logger: LoggerService;\n groupTransformer?: GroupTransformer;\n userTransformer?: UserTransformer;\n }) {\n this.providers = options.providers;\n this.logger = options.logger;\n this.groupTransformer = options.groupTransformer;\n this.userTransformer = options.userTransformer;\n }\n\n getProcessorName(): string {\n return 'LdapOrgReaderProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'ldap-org') {\n return false;\n }\n\n const provider = this.providers.find(p => location.target === p.target);\n if (!provider) {\n throw new Error(\n `There is no LDAP configuration that matches \"${location.target}\". Please add a configuration entry for it under \"ldap.providers\".`,\n );\n }\n\n // Read out all of the raw data\n const startTimestamp = Date.now();\n this.logger.info('Reading LDAP users and groups');\n\n // Be lazy and create the client each time; even though it's pretty\n // inefficient, we usually only do this once per entire refresh loop and\n // don't have to worry about timeouts and reconnects etc.\n const client = await LdapClient.create(\n this.logger,\n provider.target,\n provider.bind,\n provider.tls,\n );\n const { users, groups } = await readLdapOrg(\n client,\n provider.users,\n provider.groups,\n provider.vendor,\n {\n groupTransformer: this.groupTransformer,\n userTransformer: this.userTransformer,\n logger: this.logger,\n },\n );\n\n const duration = ((Date.now() - startTimestamp) / 1000).toFixed(1);\n this.logger.debug(\n `Read ${users.length} LDAP users and ${groups.length} LDAP groups in ${duration} seconds`,\n );\n\n // Done!\n for (const group of groups) {\n emit(processingResult.entity(location, group));\n }\n for (const user of users) {\n emit(processingResult.entity(location, user));\n }\n\n return true;\n }\n}\n"],"names":["config","readLdapLegacyConfig","client","LdapClient","readLdapOrg","processingResult"],"mappings":";;;;;;;AAsCO,MAAM,sBAAA,CAAmD;AAAA,EAC7C,SAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA;AAAA,EACA,eAAA;AAAA,EAEjB,OAAO,UAAA,CACL,UAAA,EACA,OAAA,EAKA;AAEA,IAAA,MAAMA,WACJ,UAAA,CAAW,iBAAA,CAAkB,MAAM,CAAA,IACnC,UAAA,CAAW,kBAAkB,4BAA4B,CAAA;AAC3D,IAAA,OAAO,IAAI,sBAAA,CAAuB;AAAA,MAChC,GAAG,OAAA;AAAA,MACH,SAAA,EAAWA,QAAA,GAASC,2BAAA,CAAqBD,QAAM,IAAI;AAAC,KACrD,CAAA;AAAA,EACH;AAAA,EAEA,YAAY,OAAA,EAKT;AACD,IAAA,IAAA,CAAK,YAAY,OAAA,CAAQ,SAAA;AACzB,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,mBAAmB,OAAA,CAAQ,gBAAA;AAChC,IAAA,IAAA,CAAK,kBAAkB,OAAA,CAAQ,eAAA;AAAA,EACjC;AAAA,EAEA,gBAAA,GAA2B;AACzB,IAAA,OAAO,wBAAA;AAAA,EACT;AAAA,EAEA,MAAM,YAAA,CACJ,QAAA,EACA,SAAA,EACA,IAAA,EACkB;AAClB,IAAA,IAAI,QAAA,CAAS,SAAS,UAAA,EAAY;AAChC,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAA,GAAW,KAAK,SAAA,CAAU,IAAA,CAAK,OAAK,QAAA,CAAS,MAAA,KAAW,EAAE,MAAM,CAAA;AACtE,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,6CAAA,EAAgD,SAAS,MAAM,CAAA,kEAAA;AAAA,OACjE;AAAA,IACF;AAGA,IAAA,MAAM,cAAA,GAAiB,KAAK,GAAA,EAAI;AAChC,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,+BAA+B,CAAA;AAKhD,IAAA,MAAME,QAAA,GAAS,MAAMC,iBAAA,CAAW,MAAA;AAAA,MAC9B,IAAA,CAAK,MAAA;AAAA,MACL,QAAA,CAAS,MAAA;AAAA,MACT,QAAA,CAAS,IAAA;AAAA,MACT,QAAA,CAAS;AAAA,KACX;AACA,IAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAO,GAAI,MAAMC,gBAAA;AAAA,MAC9BF,QAAA;AAAA,MACA,QAAA,CAAS,KAAA;AAAA,MACT,QAAA,CAAS,MAAA;AAAA,MACT,QAAA,CAAS,MAAA;AAAA,MACT;AAAA,QACE,kBAAkB,IAAA,CAAK,gBAAA;AAAA,QACvB,iBAAiB,IAAA,CAAK,eAAA;AAAA,QACtB,QAAQ,IAAA,CAAK;AAAA;AACf,KACF;AAEA,IAAA,MAAM,aAAa,IAAA,CAAK,GAAA,KAAQ,cAAA,IAAkB,GAAA,EAAM,QAAQ,CAAC,CAAA;AACjE,IAAA,IAAA,CAAK,MAAA,CAAO,KAAA;AAAA,MACV,QAAQ,KAAA,CAAM,MAAM,mBAAmB,MAAA,CAAO,MAAM,mBAAmB,QAAQ,CAAA,QAAA;AAAA,KACjF;AAGA,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,IAAA,CAAKG,kCAAA,CAAiB,MAAA,CAAO,QAAA,EAAU,KAAK,CAAC,CAAA;AAAA,IAC/C;AACA,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAA,CAAKA,kCAAA,CAAiB,MAAA,CAAO,QAAA,EAAU,IAAI,CAAC,CAAA;AAAA,IAC9C;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog-backend-module-ldap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "A Backstage catalog backend module that helps integrate towards LDAP",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin-module",
|
|
@@ -41,20 +41,19 @@
|
|
|
41
41
|
"test": "backstage-cli package test"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@backstage/backend-plugin-api": "1.
|
|
45
|
-
"@backstage/catalog-model": "1.7.6
|
|
46
|
-
"@backstage/config": "1.3.6
|
|
47
|
-
"@backstage/errors": "1.2.7",
|
|
48
|
-
"@backstage/plugin-catalog-common": "1.1.7
|
|
49
|
-
"@backstage/plugin-catalog-node": "1.
|
|
50
|
-
"@backstage/types": "1.2.2",
|
|
51
|
-
"
|
|
52
|
-
"ldapjs": "^2.3.3",
|
|
44
|
+
"@backstage/backend-plugin-api": "^1.5.0",
|
|
45
|
+
"@backstage/catalog-model": "^1.7.6",
|
|
46
|
+
"@backstage/config": "^1.3.6",
|
|
47
|
+
"@backstage/errors": "^1.2.7",
|
|
48
|
+
"@backstage/plugin-catalog-common": "^1.1.7",
|
|
49
|
+
"@backstage/plugin-catalog-node": "^1.20.0",
|
|
50
|
+
"@backstage/types": "^1.2.2",
|
|
51
|
+
"ldapts": "^8.0.6",
|
|
53
52
|
"lodash": "^4.17.21",
|
|
54
53
|
"uuid": "^11.0.0"
|
|
55
54
|
},
|
|
56
55
|
"devDependencies": {
|
|
57
|
-
"@backstage/cli": "0.34.5
|
|
56
|
+
"@backstage/cli": "^0.34.5",
|
|
58
57
|
"@types/lodash": "^4.14.151"
|
|
59
58
|
},
|
|
60
59
|
"configSchema": "config.d.ts",
|