]> source.dussan.org Git - archiva.git/commitdiff
Adding ldap configuration
authorMartin Stockhammer <martin_s@apache.org>
Sun, 10 Jan 2021 15:03:55 +0000 (16:03 +0100)
committerMartin Stockhammer <martin_s@apache.org>
Sun, 10 Jan 2021 15:03:55 +0000 (16:03 +0100)
15 files changed:
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/directives/nav-subgroup.directive.spec.ts [deleted file]
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/bean-information.spec.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/bean-information.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.spec.ts [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts [new file with mode: 0644]
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/base-security/base-security.component.html
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/base-security/base-security.component.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.spec.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users-roles/manage-users-roles.component.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/users/manage-users/manage-users.component.ts
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/model/page-query.spec.ts [deleted file]
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.spec.ts [deleted file]
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json

diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/directives/nav-subgroup.directive.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/directives/nav-subgroup.directive.spec.ts
deleted file mode 100644 (file)
index 295d6c0..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { NavSubgroupDirective } from './nav-subgroup.directive';
-
-describe('NavSubgroupDirective', () => {
-  it('should create an instance', () => {
-    const directive = new NavSubgroupDirective();
-    expect(directive).toBeTruthy();
-  });
-});
index 138cadce8ca1a536061c828c45d6539f6f887689..b39928ed3c389cf84b72c045c8606986e4e96bde 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 import { BeanInformation } from './bean-information';
 
 describe('BeanInformation', () => {
index 379262ab4130a8ea8784725b1f99a41f971f29b1..9a561dba101571b18e420fa3cad64491e8bcefc1 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
 export class BeanInformation {
     id: string;
     display_name: string;
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.spec.ts
new file mode 100644 (file)
index 0000000..5c11c78
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { LdapConfiguration } from './ldap-configuration';
+
+describe('LdapConfiguration', () => {
+  it('should create an instance', () => {
+    expect(new LdapConfiguration()).toBeTruthy();
+  });
+});
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts
new file mode 100644 (file)
index 0000000..94b6436
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export class LdapConfiguration {
+    host_name : string = "";
+    port : number = -1;
+    ssl_enabled : boolean  = false;
+    base_dn : string = "";
+    groups_base_dn : string = "";
+    bind_dn : string = "";
+    bind_password : string = "";
+    authentication_method : string = "";
+    bind_authenticator_enabled : boolean = true;
+    use_role_name_as_group : boolean = false;
+    properties : Map<string,string> = new Map<string, string>()
+    writable : boolean = false;
+}
index fcf545f2a45d06edb1d895f593ed3764515149b5..79945d011f45527246e119a11140605398c30b32 100644 (file)
@@ -17,6 +17,8 @@
   -->
 
 <form class="mt-3 mb-3" [formGroup]="userForm" (ngSubmit)="onSubmit()">
+    <h4>{{'security.config.base.head_managers'|translate}}</h4>
+    <p class="col-md-8">{{'security.config.base.explain_user_manager'|translate}}</p>
     <div class="row">
         <div class="col-md-4">
             <div class="drag-container">
@@ -38,6 +40,7 @@
         </div>
     </div>
 
+    <p class="col-md-8">{{'security.config.base.explain_rbac_manager'|translate}}</p>
     <div class="row">
         <div class="col-md-4">
             <div class="drag-container">
@@ -58,6 +61,7 @@
             </div>
         </div>
     </div>
+    <h4>{{'security.config.base.head_flags'|translate}}</h4>
     <div class="form-group row col-md-8">
         <div class="col-md-2">{{'security.config.base.flags'|translate}}</div>
         <div class="col-md-4">
index 4b3acf5215641fd595f27764ac56ea78cd7c22b8..04134e9f9b1b3ed7b50ef6f6b74d5ae9f9c9e871 100644 (file)
@@ -48,6 +48,17 @@ export class BaseSecurityComponent extends EditBaseComponent<SecurityConfigurati
   rbacInfo: Map<string,BeanInformation> = new Map<string, BeanInformation>();
   userInfo: Map<string,BeanInformation> = new Map<string, BeanInformation>();
 
+  constructor(private route: ActivatedRoute,
+              public fb: FormBuilder, private securityService: SecurityService, private toastService: ToastService) {
+    super(fb);
+    super.init(fb.group({
+      user_cache_enabled:[''],
+    }, {}));
+
+
+
+  }
+
   drop(event: CdkDragDrop<string[]>) {
     console.log("Drop " + event);
     if (event.previousContainer === event.container) {
@@ -60,17 +71,8 @@ export class BaseSecurityComponent extends EditBaseComponent<SecurityConfigurati
     }
   }
 
-  constructor(private route: ActivatedRoute,
-              public fb: FormBuilder, private securityService: SecurityService, private toastService: ToastService) {
-    super(fb);
-    super.init(fb.group({
-      user_cache_enabled:[''],
-    }, {}));
-
 
 
-  }
-
   ngOnInit(): void {
     zip(this.securityService.getRbacManagers(),this.securityService.getUserManagers()).pipe(tap(([rbacInfo,userInfo])=>{
       rbacInfo.forEach(info => this.rbacInfo.set(info.id, info));
index 55895d827952689fe287b18e7f68cb87e45a74b3..e982398949c8d8731d6e8493615bfe516ab3ed6b 100644 (file)
   ~ under the License.
   -->
 
-<p>ldap-security works!</p>
+<form class="mt-3 mb-3" [formGroup]="userForm" (ngSubmit)="onSubmit()">
+    <p class="row col-md-10">{{'security.config.ldap.explain'|translate}}</p>
+    <div class="form-group row col-md-10" *ngFor="let attName of ['host_name','port','base_dn','groups_base_dn','bind_dn','bind_password']">
+        <label class="col-md-3 col-form-label" for="{{attName}}">{{'security.config.ldap.attributes.'+attName |translate}}</label>
+        <div [attr.class]="attName=='port'?'col-md-3':'col-md-7'">
+            <input [attr.type]="attName=='bind_password'?'password':'text'" formControlName="{{attName}}" id="{{attName}}"
+                   [ngClass]="getInputClasses(attName)"
+            >
+        </div>
+    </div>
+    <div class="form-group row col-md-10" >
+        <label class="col-md-3 col-form-label" for="authentication_method">{{'security.config.ldap.attributes.authentication_method' |translate}}</label>
+        <div class="col-md-2">
+            <select formControlName="authentication_method" id="authentication_method" class="form-control">
+                <option *ngFor="let method of authenticationMethods">{{method}}</option>
+            </select>
+        </div>
+    </div>
+    <div class="form-group row col-md-10">
+        <div class="col-md-3">{{'security.config.ldap.flags'|translate}}</div>
+        <div class="col-md-7">
+            <div class="form-check" *ngFor="let flagName of ['writable','ssl_enabled','bind_authenticator_enabled','use_role_name_as_group']">
+                <input class="form-check-input" type="checkbox" formControlName="{{flagName}}"
+                       id="{{flagName}}" >
+                <label class="form-check-label " for="{{flagName}}">
+                    {{'security.config.ldap.attributes.'+flagName|translate}}
+                </label>
+            </div>
+        </div>
+    </div>
+
+</form>
index 7de23ee3fb0332135b0fa87ed4604045cf3c5527..85bcf6b6a5e0b099c787197b777e1052c52d269b 100644 (file)
@@ -18,7 +18,8 @@
 
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { LdapSecurityComponent } from './ldap-security.component';
+import { LdapSecurityComponent, dnValidator } from './ldap-security.component';
+import {ValidatorFn} from "@angular/forms";
 
 describe('LdapSecurityComponent', () => {
   let component: LdapSecurityComponent;
@@ -40,4 +41,17 @@ describe('LdapSecurityComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  describe('Test Custom DN Validator', () => {
+    it('check valid 1', () => {
+      const ctrl = component.userForm.controls['base_dn']
+      ctrl.setValue('cn=abc');
+      expect(ctrl.valid).toBeTruthy();
+    })
+    it('check invalid 1', () => {
+      const ctrl = component.userForm.controls['base_dn']
+      ctrl.setValue('cn=abc,');
+      expect(ctrl.invalid).toBeTruthy()
+    })
+  });
 });
index 3c3b09588526eac641b9f4926b15e1bf407a6ad6..7cc829eebc453a88a334d24de284a67de091ddfb 100644 (file)
  */
 
 import { Component, OnInit } from '@angular/core';
+import {EditBaseComponent} from "@app/modules/shared/edit-base.component";
+import {LdapConfiguration} from "@app/model/ldap-configuration";
+import {ActivatedRoute} from "@angular/router";
+import {AbstractControl, FormBuilder, ValidatorFn, Validators} from "@angular/forms";
+import {SecurityService} from "@app/services/security.service";
+import {ToastService} from "@app/services/toast.service";
+import {propertyDescriptorPatch} from "zone.js/lib/browser/property-descriptor";
 
 @Component({
   selector: 'app-ldap-security',
   templateUrl: './ldap-security.component.html',
   styleUrls: ['./ldap-security.component.scss']
 })
-export class LdapSecurityComponent implements OnInit {
+export class LdapSecurityComponent extends EditBaseComponent<LdapConfiguration> implements OnInit {
 
-  constructor() { }
+  authenticationMethods=['none','simple','strong']
+
+  constructor(private route: ActivatedRoute,
+              public fb: FormBuilder, private securityService: SecurityService, private toastService: ToastService) {
+    super(fb);
+    super.init(fb.group({
+      host_name:[''],
+      port:['', [Validators.min(1), Validators.max(65535)]],
+      ssl_enabled:[false],
+      base_dn:['',[dnValidator()]],
+      groups_base_dn:['',[dnValidator()]],
+      bind_dn:['',[dnValidator()]],
+      bind_password:[''],
+      authentication_method:['none'],
+      bind_authenticator_enabled:[false],
+      use_role_name_as_group:[true],
+      writable:[false]
+    }, {}));
+  }
 
   ngOnInit(): void {
   }
 
+  createEntity(): LdapConfiguration {
+    return new LdapConfiguration();
+  }
+
+  onSubmit() {
+  }
+
+  getInputClasses(field: string) : string[] {
+    let csClasses = super.isValid(field);
+    if (csClasses.length==1 && csClasses[0]=='') {
+      csClasses = [];
+    }
+    csClasses.push('form-control');
+    console.log("Classes "+field+" " + csClasses);
+    return csClasses;
+  }
+}
+
+export function dnValidator(): ValidatorFn {
+  return (control: AbstractControl): {[key: string]: any} | null => {
+    let parts = []
+    let value = control.value.toString()
+    let escape = false;
+    let partKey : string = ''
+    let partValue : string = ''
+    let key = true;
+    for (let i=0; i<value.length; i+=1) {
+      let c = value.charAt(i);
+      if (c=='\\' && !escape) {
+        escape = true;
+      } else if (c==',' && !escape) {
+        parts.push( [partKey,partValue]);
+        if (partKey.length==0) {
+          return {'invalidDnBadKey':{value:value,index:i}}
+        }
+        if (partValue.length==0) {
+          return {'invalidDnBadValue':{value:value, index: i}}
+        }
+        partKey='';
+        partValue='';
+        key=true;
+        continue;
+      } else if (c=='=' && !escape) {
+        if (!key) {
+          return {'invalidDnBadEquals':{value: value, index:i}}
+        }
+        key=false;
+        continue;
+      } else if (escape) {
+        escape = false;
+      }
+      if (key) {
+        partKey = partKey + c;
+      } else {
+        partValue = partValue + c;
+      }
+
+    }
+    return null;
+  };
 }
index 9608bba0b9ef32d57661d1ff0c7139ebecf3f67d..cd2d3fcaa483b2d98abc4e898a4f6c2949e64aae 100644 (file)
@@ -24,10 +24,9 @@ import {catchError, filter, map, share, switchMap, tap} from "rxjs/operators";
 import {RoleTree} from "@app/model/role-tree";
 import {RoleService} from "@app/services/role.service";
 import {RoleTemplate} from "@app/model/role-template";
-import {Observable} from "rxjs";
+import {from, Observable} from "rxjs";
 import {Util} from "@app/modules/shared/shared.module";
 import {RoleResult} from './role-result';
-import {fromArray} from "rxjs/internal/observable/fromArray";
 import {ErrorResult} from "@app/model/error-result";
 import {HttpResponse} from "@angular/common/http";
 
@@ -309,7 +308,7 @@ export class ManageUsersRolesComponent implements OnInit, AfterViewInit {
           })
         }
     )
-    fromArray(assignments).pipe(switchMap((role) => this.roleService.assignRole(role.id, this.userid)),
+    from(assignments).pipe(switchMap((role) => this.roleService.assignRole(role.id, this.userid)),
         catchError((err: ErrorResult, caught) => {
               this.success = false;
               this.errors.push(err);
@@ -321,7 +320,7 @@ export class ManageUsersRolesComponent implements OnInit, AfterViewInit {
           this.saved=true;
         }
     );
-    fromArray(unassignments).pipe(switchMap((role) => this.roleService.unAssignRole(role.id, this.userid)),
+    from(unassignments).pipe(switchMap((role) => this.roleService.unAssignRole(role.id, this.userid)),
         catchError((err: ErrorResult, caught) => {
               this.success = false;
               this.errors.push(err);
index 8ad6c3ef7fe21f3837604aa7522f50629579abaa..16347d9d8773f605df802a4830dd5272248c05bb 100644 (file)
  * under the License.
  */
 
-import {AfterViewInit, Component, OnInit} from '@angular/core';
-import {ActivatedRoute, Params} from "@angular/router";
-import {iif, Observable, of, pipe, merge, combineLatest} from "rxjs";
-import {combineAll, filter, map, mergeMap, share, switchMap, tap} from 'rxjs/operators';
-import {flatMap} from "rxjs/internal/operators";
-import {fromArray} from "rxjs/internal/observable/fromArray";
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute} from "@angular/router";
+import {merge, Observable} from "rxjs";
+import {map} from 'rxjs/operators';
 
 @Component({
   selector: 'app-manage-users',
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/model/page-query.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/model/page-query.spec.ts
deleted file mode 100644 (file)
index 13b03a1..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { PageQuery } from './page-query';
-
-describe('PageQuery', () => {
-  it('should create an instance', () => {
-    expect(new PageQuery()).toBeTruthy();
-  });
-});
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.spec.ts b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/paginated-entities/paginated-entities.component.spec.ts
deleted file mode 100644 (file)
index 0bd4fc8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { PaginatedEntitiesComponent } from './paginated-entities.component';
-
-describe('PaginatedEntitiesComponent', () => {
-  let component: PaginatedEntitiesComponent;
-  let fixture: ComponentFixture<PaginatedEntitiesComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [ PaginatedEntitiesComponent ]
-    })
-    .compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(PaginatedEntitiesComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
index 834a1a21ac90b90afdfd7780e0811db21e5b7baf..5bffc14122d165685494daba51d1607cc65c6949 100644 (file)
     "config": {
       "base": {
         "head": "Base Configuration",
+        "title": "Configure base security settings",
+        "head_managers": "Set the used User and RBAC managers",
+        "head_flags": "Additional flags",
+        "explain_user_manager": "User managers are binding your User IDs and authentication to a persistent storage or repository. You may combine them, but you have to ensure, that user IDs are unique over all repositories.",
+        "explain_rbac_manager": "RBAC managers handle roles and permissions and store them persistently. If you use LDAP, the roles are mapped to LDAP groups.",
         "flags": "Flags",
         "user_manager" : {
           "active_list" : "Active User Managers",
           "ldap_active": "LDAP Active",
           "user_cache_enabled": "User Cache Enabled"
         },
-        "submit_success": "The Changes were submitted successfully",
+        "submit_success": "The Changes were submitted successfully. A restart may be required to activate the changes.",
         "submit_error": "There was an error during submit: {error}",
         "submit_active_empty": "There must be at least on active User and RBAC Manager defined"
       },
       "ldap": {
-        "head": "LDAP Configuration"
+        "head": "LDAP Configuration",
+        "explain": "Settings for the LDAP connection. These settings are only used, if LDAP User Manager and/or LDAP RBAC Manager is activated.",
+        "attributes": {
+          "host_name": "Host Name",
+          "port": "Port",
+          "base_dn": "Base DN",
+          "groups_base_dn": "Base DN for Group Search",
+          "bind_dn": "Bind User DN",
+          "bind_password":"Bind Password",
+          "authentication_method": "Method used for Bind Authentication",
+          "bind_authenticator_enabled": "Use LDAP Bind during archiva authentication",
+          "use_role_name_as_group": "Archiva role names are LDAP group names",
+          "writable": "Bind User can write to LDAP Server",
+          "ssl_enabled": "Enable SSL"
+
+        },
+        "flags": "Flags"
       }
     }
   },