mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-10 21:33:20 +00:00
starttls: Support LDAP STARTTLS (#33)
* starttls: Support LDAP STARTTLS * starttls: Re-roll to preserve old config
This commit is contained in:
@@ -35,39 +35,54 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="ssl" [(ngModel)]="ldap.ssl" name="SSL">
|
<input class="form-check-input" type="checkbox" id="ldapEncrypted" [(ngModel)]="ldap.ssl" name="Encrypted">
|
||||||
<label class="form-check-label" for="ssl">{{'ldapSsl' | i18n}}</label>
|
<label class="form-check-label" for="ldapEncrypted">{{'ldapEncrypted' | i18n}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-4" *ngIf="ldap.ssl">
|
<div class="ml-4" *ngIf="ldap.ssl">
|
||||||
<p>{{'ldapSslUntrustedDesc' | i18n}}</p>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="sslCertPath">{{'ldapSslCert' | i18n}}</label>
|
<div class="form-radio">
|
||||||
<input type="file" class="form-control-file mb-2" id="sslCertPath_file"
|
<input class="form-radio-input" type="radio" [value]=true id="starttls" [(ngModel)]="ldap.starttls" name="StartTls">
|
||||||
(change)="setSslPath('sslCertPath')">
|
<label class="form-radio-label" for="starttls">{{'ldapTls' | i18n}}</label>
|
||||||
<input type="text" class="form-control" id="sslCertPath" name="SSLCertPath"
|
</div>
|
||||||
[(ngModel)]="ldap.sslCertPath">
|
<div class="form-radio">
|
||||||
|
<input class="form-radio-input" type="radio" [value]=false id="ssl" [(ngModel)]="ldap.starttls" name="SSL">
|
||||||
|
<label class="form-radio-label" for="ssl">{{'ldapSsl' | i18n}}</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="ml-4" *ngIf="ldap.starttls">
|
||||||
<label for="sslKeyPath">{{'ldapSslKey' | i18n}}</label>
|
<p>{{'ldapTlsUntrustedDesc' | i18n}}</p>
|
||||||
<input type="file" class="form-control-file mb-2" id="sslKeyPath_file"
|
<div class="form-group">
|
||||||
(change)="setSslPath('sslKeyPath')">
|
<label for="tlsCaPath">{{'ldapTlsCa' | i18n}}</label>
|
||||||
<input type="text" class="form-control" id="sslKeyPath" name="SSLKeyPath"
|
<input type="file" class="form-control-file mb-2" id="tlsCaPath_file"
|
||||||
[(ngModel)]="ldap.sslKeyPath">
|
(change)="setSslPath('tlsCaPath')">
|
||||||
|
<input type="text" class="form-control" id="tlsCaPath" name="TLSCaPath" [(ngModel)]="ldap.tlsCaPath">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="ml-4" *ngIf="!ldap.starttls">
|
||||||
<label for="sslCaPath">{{'ldapSslCa' | i18n}}</label>
|
<p>{{'ldapSslUntrustedDesc' | i18n}}</p>
|
||||||
<input type="file" class="form-control-file mb-2" id="sslCaPath_file"
|
<div class="form-group">
|
||||||
(change)="setSslPath('sslCaPath')">
|
<label for="sslCertPath">{{'ldapSslCert' | i18n}}</label>
|
||||||
<input type="text" class="form-control" id="sslCaPath" name="SSLCaPath"
|
<input type="file" class="form-control-file mb-2" id="sslCertPath_file"
|
||||||
[(ngModel)]="ldap.sslCaPath">
|
(change)="setSslPath('sslCertPath')">
|
||||||
|
<input type="text" class="form-control" id="sslCertPath" name="SSLCertPath" [(ngModel)]="ldap.sslCertPath">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sslKeyPath">{{'ldapSslKey' | i18n}}</label>
|
||||||
|
<input type="file" class="form-control-file mb-2" id="sslKeyPath_file" (change)="setSslPath('sslKeyPath')">
|
||||||
|
<input type="text" class="form-control" id="sslKeyPath" name="SSLKeyPath" [(ngModel)]="ldap.sslKeyPath">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="sslCaPath">{{'ldapSslCa' | i18n}}</label>
|
||||||
|
<input type="file" class="form-control-file mb-2" id="sslCaPath_file" (change)="setSslPath('sslCaPath')">
|
||||||
|
<input type="text" class="form-control" id="sslCaPath" name="SSLCaPath" [(ngModel)]="ldap.sslCaPath">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="sslAllowUnauthorized"
|
<input class="form-check-input" type="checkbox" id="certDoNotVerify"
|
||||||
[(ngModel)]="ldap.sslAllowUnauthorized" name="SSLAllowUnauthorized">
|
[(ngModel)]="ldap.sslAllowUnauthorized" name="CertDoNoVerify">
|
||||||
<label class="form-check-label"
|
<label class="form-check-label" for="certDoNotVerify">{{'ldapCertDoNotVerify' | i18n}}</label>
|
||||||
for="sslAllowUnauthorized">{{'ldapSslAllowUnauthorized' | i18n}}</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -414,8 +414,20 @@
|
|||||||
"sync": {
|
"sync": {
|
||||||
"message": "Sync"
|
"message": "Sync"
|
||||||
},
|
},
|
||||||
|
"ldapEncrypted": {
|
||||||
|
"message": "This server uses an encrypted connection"
|
||||||
|
},
|
||||||
|
"ldapTls": {
|
||||||
|
"message": "Use TLS (STARTTLS)"
|
||||||
|
},
|
||||||
|
"ldapTlsCa": {
|
||||||
|
"message": "Certificate CA Chain (PEM)"
|
||||||
|
},
|
||||||
"ldapSsl": {
|
"ldapSsl": {
|
||||||
"message": "This server uses SSL (LDAPS)"
|
"message": "Use SSL (LDAPS)"
|
||||||
|
},
|
||||||
|
"ldapTlsUntrustedDesc": {
|
||||||
|
"message": "If your LDAP server uses a self-signed certificate for STARTTLS, you can configure certificate options below."
|
||||||
},
|
},
|
||||||
"ldapSslUntrustedDesc": {
|
"ldapSslUntrustedDesc": {
|
||||||
"message": "If your LDAPS server uses an untrusted certificate you can configure certificate options below."
|
"message": "If your LDAPS server uses an untrusted certificate you can configure certificate options below."
|
||||||
@@ -429,8 +441,8 @@
|
|||||||
"ldapSslKey": {
|
"ldapSslKey": {
|
||||||
"message": "Certificate Private Key (PEM)"
|
"message": "Certificate Private Key (PEM)"
|
||||||
},
|
},
|
||||||
"ldapSslAllowUnauthorized": {
|
"ldapCertDoNotVerify": {
|
||||||
"message": "Allow untrusted SSL connections (not recommended)."
|
"message": "Do not verify server certificates (not recommended)."
|
||||||
},
|
},
|
||||||
"ldapAd": {
|
"ldapAd": {
|
||||||
"message": "This server uses Active Directory"
|
"message": "This server uses Active Directory"
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
export class LdapConfiguration {
|
export class LdapConfiguration {
|
||||||
ssl = false;
|
ssl = false;
|
||||||
|
starttls = true;
|
||||||
|
tlsCaPath: string;
|
||||||
sslAllowUnauthorized = false;
|
sslAllowUnauthorized = false;
|
||||||
sslCertPath: string;
|
sslCertPath: string;
|
||||||
sslKeyPath: string;
|
sslKeyPath: string;
|
||||||
|
|||||||
@@ -324,32 +324,41 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
reject(this.i18nService.t('dirConfigIncomplete'));
|
reject(this.i18nService.t('dirConfigIncomplete'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const protocol = 'ldap' + (this.dirConfig.ssl && !this.dirConfig.starttls ? 's' : '');
|
||||||
const url = 'ldap' + (this.dirConfig.ssl ? 's' : '') + '://' + this.dirConfig.hostname +
|
const url = protocol + '://' + this.dirConfig.hostname +
|
||||||
':' + this.dirConfig.port;
|
':' + this.dirConfig.port;
|
||||||
const options: ldap.ClientOptions = {
|
const options: ldap.ClientOptions = {
|
||||||
url: url.trim().toLowerCase(),
|
url: url.trim().toLowerCase(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tlsOptions: any = {};
|
||||||
if (this.dirConfig.ssl) {
|
if (this.dirConfig.ssl) {
|
||||||
const tlsOptions: any = {};
|
if (!this.dirConfig.starttls) {
|
||||||
if (this.dirConfig.sslAllowUnauthorized != null) {
|
if (this.dirConfig.sslCaPath != null && this.dirConfig.sslCaPath !== '' &&
|
||||||
|
fs.existsSync(this.dirConfig.sslCaPath)) {
|
||||||
|
tlsOptions.ca = [fs.readFileSync(this.dirConfig.sslCaPath)];
|
||||||
|
}
|
||||||
|
if (this.dirConfig.sslCertPath != null && this.dirConfig.sslCertPath !== '' &&
|
||||||
|
fs.existsSync(this.dirConfig.sslCertPath)) {
|
||||||
|
tlsOptions.cert = fs.readFileSync(this.dirConfig.sslCertPath);
|
||||||
|
}
|
||||||
|
if (this.dirConfig.sslKeyPath != null && this.dirConfig.sslKeyPath !== '' &&
|
||||||
|
fs.existsSync(this.dirConfig.sslKeyPath)) {
|
||||||
|
tlsOptions.key = fs.readFileSync(this.dirConfig.sslKeyPath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.dirConfig.tlsCaPath != null && this.dirConfig.tlsCaPath !== '' &&
|
||||||
|
fs.existsSync(this.dirConfig.tlsCaPath)) {
|
||||||
|
tlsOptions.ca = [fs.readFileSync(this.dirConfig.tlsCaPath)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.dirConfig.sslAllowUnauthorized) {
|
||||||
tlsOptions.rejectUnauthorized = !this.dirConfig.sslAllowUnauthorized;
|
tlsOptions.rejectUnauthorized = !this.dirConfig.sslAllowUnauthorized;
|
||||||
}
|
}
|
||||||
if (this.dirConfig.sslCaPath != null && this.dirConfig.sslCaPath !== '' &&
|
}
|
||||||
fs.existsSync(this.dirConfig.sslCaPath)) {
|
|
||||||
tlsOptions.ca = [fs.readFileSync(this.dirConfig.sslCaPath)];
|
if (Object.keys(tlsOptions).length > 0) {
|
||||||
}
|
options.tlsOptions = tlsOptions;
|
||||||
if (this.dirConfig.sslCertPath != null && this.dirConfig.sslCertPath !== '' &&
|
|
||||||
fs.existsSync(this.dirConfig.sslCertPath)) {
|
|
||||||
tlsOptions.cert = fs.readFileSync(this.dirConfig.sslCertPath);
|
|
||||||
}
|
|
||||||
if (this.dirConfig.sslKeyPath != null && this.dirConfig.sslKeyPath !== '' &&
|
|
||||||
fs.existsSync(this.dirConfig.sslKeyPath)) {
|
|
||||||
tlsOptions.key = fs.readFileSync(this.dirConfig.sslKeyPath);
|
|
||||||
}
|
|
||||||
if (Object.keys(tlsOptions).length > 0) {
|
|
||||||
options.tlsOptions = tlsOptions;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client = ldap.createClient(options);
|
this.client = ldap.createClient(options);
|
||||||
@@ -364,13 +373,29 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client.bind(user, pass, (err) => {
|
if (this.dirConfig.starttls && this.dirConfig.ssl) {
|
||||||
if (err != null) {
|
this.client.starttls(options.tlsOptions, undefined, (err, res) => {
|
||||||
reject(err.message);
|
if (err != null) {
|
||||||
} else {
|
reject(err.message);
|
||||||
resolve();
|
} else {
|
||||||
}
|
this.client.bind(user, pass, (err) => {
|
||||||
});
|
if (err != null) {
|
||||||
|
reject(err.message);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.client.bind(user, pass, (err) => {
|
||||||
|
if (err != null) {
|
||||||
|
reject(err.message);
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user