11import { Config } from "../config" ;
2- import ldap from "ldapjs" ;
3- import ldapEscape from "ldap-escape" ;
42import axios from "axios" ;
53import axiosRetry from "axios-retry" ;
6- import { Log , LogError , LoggerToUse } from "../logging" ;
4+ import { Log , LoggerToUse } from "../logging" ;
75import { redisClient } from "../app" ;
86
97const config = Config ( )
10-
11- let client : ldap . Client ;
12-
13- if ( ! process . env . SOURCE_PROXY ) {
14- client = ldap . createClient ( {
15- url : [ config . LDAP . Server ]
16- } ) ;
17-
18- client . bind ( config . LDAP . User , config . LDAP . Password , ( err ) => {
19- if ( err ) {
20- console . log ( "Failed to connect to LDAP Server" ) ;
21- LogError ( JSON . stringify ( err ) as string ) ;
22- }
23-
24- console . log ( "Connected to LDAP Server" ) ;
25- } ) ;
26- }
27- else {
28- Log ( "Group Proxy is set. LDAP will not be configured for this instance." )
29- }
30-
31- function SearchAsync ( groupName : string ) : Promise < ldap . SearchCallbackResponse > {
32- const component = ldapEscape . filter `${ groupName } ` ;
33- const ldapSearchString = `(&(objectCategory=user)(memberOf=CN=${ component } ,CN=Users,${ config . LDAP . GroupBaseDN } ))`
34-
35- const opts : ldap . SearchOptions = {
36- filter : ldapSearchString ,
37- scope : "sub" ,
38- // paged:true
39- attributes : [ 'dn' , 'cn' , 'userPrincipalName' ] ,
40- // paged: {
41- // pageSize: 250,
42- // pagePause: true
43- // }
44- } ;
45-
46- return new Promise ( ( resolve , reject ) => {
47- client . search ( config . LDAP . GroupBaseDN , opts , ( err , res ) => {
48- if ( err ) {
49- LogError ( `Error searching for ${ component } : ${ JSON . stringify ( err ) } ` )
50- return reject ( err ) ;
51- }
52-
53- return resolve ( res ) ;
54- } ) ;
55- } )
56- }
57-
588export interface Entry {
599 cn : string ,
6010 userPrincipalName : string
@@ -71,56 +21,6 @@ export type SearchAllSucceeded = {
7121
7222export type SearchAllResponse = Promise < SearchAllFailed | SearchAllSucceeded >
7323
74- async function SearchAllAsyncNoExceptionHandling ( groupName : string ) : SearchAllResponse {
75- // TODO: implement paging somehow!!
76- const response = await SearchAsync ( groupName ) ;
77-
78- const entries : Entry [ ] = [ ] ;
79-
80- type rawEntry = {
81- pojo : {
82- attributes : {
83- type :string ,
84- values :string [ ]
85- } [ ]
86- }
87- }
88-
89- return new Promise ( ( resolve , reject ) => {
90- response . on ( 'searchEntry' , ( entry : rawEntry ) => {
91- const attributes = entry . pojo . attributes . map ( ( a ) => {
92- return [
93- a . type ,
94- a . values [ 0 ]
95- ]
96- } )
97- entries . push ( Object . fromEntries ( attributes ) as Entry ) ;
98- } ) ;
99-
100- type result = {
101- status :number
102- }
103-
104- response . on ( 'end' , ( result : result ) => {
105- Log ( `Search Ended for Group '${ groupName } ' with result '${ JSON . stringify ( result ) } '` )
106-
107- if ( result == null || result == undefined || result . status !== 0 ) {
108- return reject ( result . status ) ;
109- }
110-
111- return resolve ( {
112- entries : entries ,
113- Succeeded : true
114- } ) ;
115- } ) ;
116-
117- response . on ( 'error' , ( err : unknown ) => {
118- LogError ( `Search Errored for Group '${ groupName } ': ${ JSON . stringify ( err ) } ` ) ;
119- return reject ( ) ;
120- } ) ;
121- } ) ;
122- }
123-
12424export async function SearchAllAsync ( groupName : string ) : SearchAllResponse {
12525 const cacheKey = `sot-group:${ groupName } ` ;
12626
@@ -138,7 +38,8 @@ export async function SearchAllAsync(groupName: string): SearchAllResponse {
13838 return JSON . parse ( result ) as SearchAllResponse
13939 }
14040
141- const actualResult = await PrivateSearchAllAsync ( groupName ) ;
41+ // Make API call here
42+ const actualResult = await ForwardSearch ( groupName ) ;
14243
14344 // Slightly complex for caching logic, but we don't want to cache useless results
14445 if ( actualResult . Succeeded && actualResult . entries . length > 0 ) {
@@ -150,28 +51,11 @@ export async function SearchAllAsync(groupName: string): SearchAllResponse {
15051 return actualResult ;
15152}
15253
153- async function PrivateSearchAllAsync ( groupName : string ) : SearchAllResponse {
154- try {
155- if ( process . env . SOURCE_PROXY ) {
156- return await ForwardSearch ( groupName ) ;
157- }
158-
159- return await SearchAllAsyncNoExceptionHandling ( groupName ) ;
160- }
161- catch ( ex : unknown ) {
162- Log ( JSON . stringify ( ex ) ) ;
163-
164- return {
165- Succeeded : false
166- }
167- }
168- }
169-
17054// TODO: do not directly use axios.create from within a function like this
17155// it will cause a new client to be made per request.
17256const httpClient = axios . create ( ) ;
17357axiosRetry ( httpClient , {
174- retries : 5 ,
58+ retries : 2 ,
17559 retryDelay : ( retryCount ) => {
17660 Log ( `Retry attempt: ${ retryCount } ` ) ;
17761 return retryCount * 2000 ;
@@ -188,15 +72,29 @@ axiosRetry(httpClient, {
18872async function ForwardSearch ( groupName : string ) : SearchAllResponse {
18973 Log ( `Forwarding request to '${ process . env . SOURCE_PROXY } '` ) ;
19074
191- const requestUrl = `${ process . env . SOURCE_PROXY } /api/get-source-team?teamName= ${ groupName } ` ;
75+ const requestUrl = `${ process . env . SOURCE_PROXY } /search/ ${ groupName } ` ;
19276
19377 Log ( `Retrieving group (${ groupName } ) information from '${ requestUrl } '` ) ;
19478 try {
195- const result = await httpClient . get ( requestUrl ) ;
196- Log ( `Results for ${ groupName } : ${ result } ` ) ;
79+ const httpResponse = await httpClient . get ( requestUrl ) ;
80+ Log ( `Results for ${ groupName } : ${ JSON . stringify ( httpResponse . data ) } ` ) ;
81+
82+ if ( httpResponse . status < 200 || httpResponse . status > 299 ) {
83+ return {
84+ Succeeded : false
85+ }
86+ }
87+
88+ const response = httpResponse . data as SuccessResponse ;
89+
19790 return {
19891 Succeeded : true ,
199- ...result . data
92+ entries : response . users . map ( u => {
93+ return {
94+ cn : u . username ,
95+ userPrincipalName : u . email
96+ }
97+ } )
20098 }
20199 }
202100 catch ( e ) {
@@ -207,3 +105,18 @@ async function ForwardSearch(groupName: string): SearchAllResponse {
207105 Succeeded : false
208106 }
209107}
108+
109+ export interface User {
110+ username : string
111+ email : string
112+ }
113+
114+ export interface SuccessResponse {
115+ users : User [ ]
116+ }
117+
118+ export interface FailedResponse {
119+ Message : string
120+ }
121+
122+ export type SearchResponse = SuccessResponse | FailedResponse
0 commit comments