This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/archiva.git

commit 0dc2e8fff6e21178b62d10982e34067655ff6524
Author: Martin Stockhammer <[email protected]>
AuthorDate: Mon Jan 11 16:53:37 2021 +0100

    Improving LDAP configuration
---
 .../rest/api/model/v2/LdapConfiguration.java       |  1 +
 .../services/v2/SecurityConfigurationService.java  |  4 +-
 .../v2/DefaultSecurityConfigurationService.java    | 29 +++++++--
 .../archiva-web/src/app/model/app-notification.ts  |  2 +-
 .../src/app/model/ldap-configuration.ts            | 25 +++++++-
 ...{ldap-configuration.ts => property-map.spec.ts} | 23 +++-----
 .../{ldap-configuration.ts => property-map.ts}     | 26 ++++----
 .../ldap-security/ldap-security.component.html     | 31 +++++++++-
 .../ldap-security/ldap-security.component.ts       | 69 ++++++++++++++++++++--
 .../shared/toast/toast.component.scss}             | 47 ++++++++++-----
 .../app/modules/shared/toast/toast.component.ts    |  5 +-
 .../src/app/services/security.service.ts           | 19 ++++--
 .../archiva-web/src/app/services/toast.service.ts  |  6 +-
 .../src/main/archiva-web/src/assets/i18n/en.json   | 11 +++-
 14 files changed, 223 insertions(+), 75 deletions(-)

diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java
index ae789a1..d6802c6 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/model/v2/LdapConfiguration.java
@@ -64,6 +64,7 @@ public class LdapConfiguration implements Serializable
         newCfg.setBindAuthenticatorEnabled( 
ldapConfiguration.isBindAuthenticatorEnabled() );
         newCfg.setHostName( ldapConfiguration.getHostName( ) );
         newCfg.setSslEnabled( ldapConfiguration.isSsl() );
+        newCfg.setContextFactory( ldapConfiguration.getContextFactory() );
         if (ldapConfiguration.getPort()<=0) {
             newCfg.setPort( newCfg.isSslEnabled() ? 636 : 389 );
         } else
diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java
index aa02581..9471649 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/v2/SecurityConfigurationService.java
@@ -107,7 +107,7 @@ public interface SecurityConfigurationService
                 content = @Content(mediaType = APPLICATION_JSON, schema = 
@Schema(implementation = ArchivaRestError.class )) )
         }
     )
-    Response updateConfiguration( SecurityConfiguration newConfiguration)
+    SecurityConfiguration updateConfiguration( SecurityConfiguration 
newConfiguration)
         throws ArchivaRestServiceException;
 
 
@@ -239,7 +239,7 @@ public interface SecurityConfigurationService
                 content = @Content(mediaType = APPLICATION_JSON, schema = 
@Schema(implementation = ArchivaRestError.class )) )
         }
     )
-    Response updateLdapConfiguration( LdapConfiguration configuration ) throws 
ArchivaRestServiceException;
+    LdapConfiguration updateLdapConfiguration( LdapConfiguration configuration 
) throws ArchivaRestServiceException;
 
     @Path("config/ldap/verify")
     @POST
diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java
index 80e65c2..3ecda4a 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/v2/DefaultSecurityConfigurationService.java
@@ -182,6 +182,7 @@ public class DefaultSecurityConfigurationService implements 
SecurityConfiguratio
         ldapConfig.setPassword( newConfig.getBindPassword( ) );
         ldapConfig.setUseRoleNameAsGroup( newConfig.isUseRoleNameAsGroup( ) );
         ldapConfig.setWritable( newConfig.isWritable( ) );
+        ldapConfig.setContextFactory( newConfig.getContextFactory( ) );
 
         Map<String, String> props = ldapConfig.getExtraProperties( );
         for ( Map.Entry<String, String> newProp : newConfig.getProperties( 
).entrySet( ) )
@@ -200,7 +201,7 @@ public class DefaultSecurityConfigurationService implements 
SecurityConfiguratio
     }
 
     @Override
-    public Response updateConfiguration( SecurityConfiguration 
newConfiguration ) throws ArchivaRestServiceException
+    public SecurityConfiguration updateConfiguration( SecurityConfiguration 
newConfiguration ) throws ArchivaRestServiceException
     {
         if ( newConfiguration == null )
         {
@@ -308,7 +309,15 @@ public class DefaultSecurityConfigurationService 
implements SecurityConfiguratio
         {
             throw new ArchivaRestServiceException( ErrorMessage.of( 
REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
         }
-        return Response.ok( ).build( );
+        try
+        {
+            return SecurityConfiguration.ofRedbackConfiguration( 
redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( ) );
+        }
+        catch ( RepositoryAdminException e )
+        {
+            log.error( "Error while retrieve updated configuration: {}", 
e.getMessage( ) );
+            throw new ArchivaRestServiceException( ErrorMessage.of( 
REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
+        }
     }
 
     @Override
@@ -414,7 +423,7 @@ public class DefaultSecurityConfigurationService implements 
SecurityConfiguratio
     }
 
     @Override
-    public Response updateLdapConfiguration( LdapConfiguration configuration ) 
throws ArchivaRestServiceException
+    public LdapConfiguration updateLdapConfiguration( LdapConfiguration 
configuration ) throws ArchivaRestServiceException
     {
         try
         {
@@ -426,14 +435,22 @@ public class DefaultSecurityConfigurationService 
implements SecurityConfiguratio
             updateConfig( configuration, redbackRuntimeConfiguration );
 
             
redbackRuntimeConfigurationAdmin.updateRedbackRuntimeConfiguration( 
redbackRuntimeConfiguration );
-
-            return Response.ok( ).build( );
-
         }
         catch ( RepositoryAdminException e )
         {
             throw new ArchivaRestServiceException( ErrorMessage.of( 
REPOSITORY_ADMIN_ERROR ) );
         }
+
+        try
+        {
+            return LdapConfiguration.of( 
redbackRuntimeConfigurationAdmin.getRedbackRuntimeConfiguration( 
).getLdapConfiguration() );
+        }
+        catch ( RepositoryAdminException e )
+        {
+            log.error( "Error while retrieve updated configuration: {}", 
e.getMessage( ) );
+            throw new ArchivaRestServiceException( ErrorMessage.of( 
REPOSITORY_ADMIN_ERROR, e.getMessage( ) ) );
+        }
+
     }
 
     static final Properties toProperties( Map<String, String> values )
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/app-notification.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/app-notification.ts
index ae1b0a4..7522915 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/app-notification.ts
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/app-notification.ts
@@ -23,7 +23,7 @@ export class AppNotification {
     header: string;
     body: string | TemplateRef<any>;
     timestamp: Date;
-    classname: string='';
+    classname: string[]=[''];
     delay:number=5000;
     contextData:any;
     type:string='normal'
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
index eb01950..65a15ce 100644
--- 
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
@@ -16,6 +16,8 @@
  * under the License.
  */
 
+import {PropertyMap} from "@app/model/property-map";
+
 export class LdapConfiguration {
     host_name : string = "";
     port : number = 389;
@@ -28,7 +30,28 @@ export class LdapConfiguration {
     authentication_method : string = "";
     bind_authenticator_enabled : boolean = true;
     use_role_name_as_group : boolean = false;
-    properties : Map<string,string> = new Map<string, string>()
+    properties : PropertyMap;
     writable : boolean = false;
     available_context_factories : string[];
+
+
+    constructor(initObj:any=null) {
+        if (initObj) {
+            this.host_name = initObj.host_name
+            this.port = initObj.port
+            this.ssl_enabled = initObj.ssl_enabled
+            this.context_factory = initObj.context_factory
+            this.base_dn = initObj.base_dn
+            this.groups_base_dn = initObj.groups_base_dn
+            this.bind_dn = initObj.bind_dn
+            this.bind_password = initObj.bind_password
+            this.authentication_method = initObj.authentication_method
+            this.bind_authenticator_enabled = 
initObj.bind_authenticator_enabled
+            this.use_role_name_as_group = initObj.use_role_name_as_group
+            this.properties = new 
PropertyMap(Object.entries(initObj.properties))
+            this.writable = initObj.writable
+            this.available_context_factories = 
initObj.available_context_factories
+        }
+    }
+
 }
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/property-map.spec.ts
similarity index 59%
copy from 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts
copy to 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/property-map.spec.ts
index eb01950..f0b8346 100644
--- 
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/property-map.spec.ts
@@ -16,19 +16,10 @@
  * under the License.
  */
 
-export class LdapConfiguration {
-    host_name : string = "";
-    port : number = 389;
-    ssl_enabled : boolean  = false;
-    context_factory: string = "";
-    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;
-    available_context_factories : string[];
-}
+import { PropertyMap } from './property-map';
+
+describe('PropertyMap', () => {
+  it('should create an instance', () => {
+    expect(new PropertyMap()).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/property-map.ts
similarity index 59%
copy from 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts
copy to 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/property-map.ts
index eb01950..036db83 100644
--- 
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/property-map.ts
@@ -16,19 +16,15 @@
  * under the License.
  */
 
-export class LdapConfiguration {
-    host_name : string = "";
-    port : number = 389;
-    ssl_enabled : boolean  = false;
-    context_factory: string = "";
-    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;
-    available_context_factories : string[];
+export class PropertyMap extends Map<string,string> {
+
+    constructor(entries?: readonly (readonly [string, string])[] | null) {
+        super(entries);
+    }
+
+    toJSON() {
+        let object = { };
+        for (let [key, value] of this) object[key] = value;
+        return object;
+    }
 }
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html
index 5f27058..f794074 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.html
@@ -35,6 +35,7 @@
         <div class="col-md-7">
             <input type="text" formControlName="context_factory" 
id="context_factory"
                    [ngClass]="getInputClasses('context_factory')" 
[ngbTypeahead]="searchContextFactory"
+                   [placement]="top"
             >
         </div>
     </div>
@@ -60,15 +61,41 @@
             </div>
         </div>
     </div>
+    <div class="form-group row col-md-10" >
+        <div 
class="col-md-3">{{'security.config.ldap.attributes.properties'|translate}}</div>
+        <div class="col-md-7 form-row">
+            <input type="text" id="prop_key" formControlName="prop_key" 
class="form-control col" placeholder="{{'form.button.key'|translate}}"
+
+            >
+            <input type="prop_value" id="prop_value" 
formControlName="prop_value"
+                   class="form-control col" 
placeholder="{{'form.button.value'|translate}}">
+            <button type="button" class="ml-2 btn btn-primary col" 
(click)="addProperty()">{{'form.button.add'|translate}}</button>
+        </div>
+    </div>
+    <div class="form-group row col-md-10" *ngIf="ldapProperties && 
ldapProperties.size>0">
+        <div class="col-md-3"></div>
+        <div class="col-md-7 pl-2 list-group">
+                <div class="list-group-item" *ngFor="let propEntry of 
ldapProperties  |keyvalue">
+                    <span 
class="float-left">{{propEntry.key}}={{propEntry.value}}</span>
+                    <a class="float-right" [routerLink]="" 
(click)="removeProperty(propEntry.key)" ><i class="fas fa-trash-alt"></i></a>
+                </div>
+        </div>
+    </div>
+
 
     <div class="row col-md-10 mt-4">
         <button class="btn btn-primary col-md-2" type="submit"
-                [disabled]="userForm.invalid || 
!userForm.dirty">{{'form.button.save'|translate}}</button>
+                [disabled]="checkProgress|| userForm.invalid || 
!userForm.dirty">{{'form.button.save'|translate}}</button>
         <button class="btn btn-primary col-md-2 offset-1" type="button" 
(click)="checkLdapConnection()"
-                [disabled]="userForm.invalid || 
!userForm.dirty">{{'form.button.check'|translate}}</button>
+                [disabled]="checkProgress||userForm.invalid">
+            <span *ngIf="checkProgress" class="spinner-border 
spinner-border-sm" role="status" aria-hidden="true"></span>
+            <span 
*ngIf="checkProgress">&nbsp;{{'form.button.checking'|translate}}</span>
+            <span 
*ngIf="!checkProgress">{{'form.button.check'|translate}}</span></button>
     </div>
     <div class="row  col-md-10 mt-2">
         <div class="alert col-md-6 ml-1 alert-success" role="alert"
+             
*ngIf="submitError">{{'security.config.ldap.submit_error'|translate:{error:submitError.toString()}
 }}</div>
+        <div class="alert col-md-6 ml-1 alert-success" role="alert"
              
*ngIf="checkResult=='success'">{{'security.config.ldap.check_success'|translate}}</div>
         <div class="alert col-md-6 ml-1 alert-warning" role="alert"
              
*ngIf="checkResult=='error'">{{'security.config.ldap.check_failed'|translate}}</div>
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts
index f0c4eeb..03bc343 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/security/security-configuration/ldap-security/ldap-security.component.ts
@@ -26,6 +26,8 @@ import {ToastService} from "@app/services/toast.service";
 import {ErrorResult} from "@app/model/error-result";
 import {Observable} from 'rxjs';
 import {debounceTime, distinctUntilChanged, map} from 'rxjs/operators';
+import {HttpResponse} from "@angular/common/http";
+import {PropertyMap} from "@app/model/property-map";
 
 @Component({
     selector: 'app-ldap-security',
@@ -39,7 +41,10 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
         'base_dn', 'groups_base_dn', 'bind_dn', 'bind_password', 
'authentication_method', 'bind_authenticator_enabled',
         'use_role_name_as_group', 'writable'];
     availableContextFactories = [];
+    ldapProperties : PropertyMap = new PropertyMap();
     checkResult = null;
+    submitError = null;
+    checkProgress=false;
 
     constructor(private route: ActivatedRoute,
                 public fb: FormBuilder, private securityService: 
SecurityService, private toastService: ToastService) {
@@ -56,7 +61,9 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
             authentication_method: ['none'],
             bind_authenticator_enabled: [false],
             use_role_name_as_group: [true],
-            writable: [false]
+            writable: [false],
+            prop_key:[''],
+            prop_value:['']
         }, {}));
     }
 
@@ -69,7 +76,13 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
                 if (ldapConfiguration.authentication_method == '') {
                     
this.userForm.controls['authentication_method'].setValue('none');
                 }
-                this.availableContextFactories = 
ldapConfiguration.available_context_factories
+                this.availableContextFactories = 
ldapConfiguration.available_context_factories;
+            console.log("Props: " + ldapConfiguration.properties + " " + 
typeof (ldapConfiguration.properties));
+                if (ldapConfiguration.properties) {
+                    this.ldapProperties = ldapConfiguration.properties as 
PropertyMap;
+                } else {
+                    this.ldapProperties = new PropertyMap();
+                }
             }
         )
         this.userForm.controls['bind_dn'].valueChanges.subscribe(selectedValue 
=> {
@@ -79,7 +92,7 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
                 
this.userForm.controls['authentication_method'].setValue('none', {emitEvent: 
false})
             }
         })
-        this.userForm.valueChanges.subscribe(val => {
+        this.userForm.valueChanges.subscribe(() => {
             this.checkResult = null;
         })
 
@@ -92,6 +105,23 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
     onSubmit() {
         console.log("Saving configuration");
         let config = this.copyFromForm(this.formFields)
+        if (this.ldapProperties) {
+            config.properties = this.ldapProperties;
+        }
+        
this.securityService.updateLdapConfiguration(config).subscribe((response: 
HttpResponse<LdapConfiguration>)=> {
+                this.toastService.showSuccessByKey('ldap-security', 
'security.config.ldap.submit_success');
+                this.userForm.reset();
+                this.submitError=null;
+                this.checkResult=null;
+                this.copyToForm(this.formFields, response.body)
+        },
+            (error: ErrorResult) =>{
+                this.toastService.showSuccessByKey('ldap-security', 
'security.config.ldap.submit_error', {error:error.toString()});
+                this.submitError = error;
+                this.checkResult=null;
+            }
+
+        );
 
 
     }
@@ -100,7 +130,7 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
         text$.pipe(
             debounceTime(200),
             distinctUntilChanged(),
-            map(term => term.length < 2 ? []
+            map(term => term.length < 1 ? []
                 : this.availableContextFactories.filter(v => 
v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10))
         )
 
@@ -116,16 +146,44 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
     checkLdapConnection() {
         console.log("Checking LDAP connection");
         let config = this.copyFromForm(this.formFields)
+        if (this.ldapProperties) {
+            config.properties = this.ldapProperties;
+        }
+        this.checkProgress=true;
         this.securityService.verifyLdapConfiguration(config).subscribe(() => {
                 this.toastService.showSuccessByKey('ldap-security', 
'security.config.ldap.check_success');
                 this.checkResult = 'success';
+                this.checkProgress=false;
             },
             (error: ErrorResult) => {
                 this.toastService.showErrorByKey('ldap-security', 
error.firstMessageString());
                 this.checkResult = 'error';
+                this.checkProgress=false;
             }
         );
     }
+
+    addProperty() {
+        let key = this.userForm.controls['prop_key'].value
+        let value = this.userForm.controls['prop_value'].value
+
+        console.log("Prop " + key + " = " + value);
+        if (key && key!='') {
+            setTimeout(() => {
+                this.ldapProperties.set(key, value);
+                this.userForm.markAsDirty();
+            });
+        }
+        this.userForm.controls['prop_key'].setValue('')
+        this.userForm.controls['prop_value'].setValue('')
+    }
+
+    removeProperty(key:string) {
+        setTimeout(()=>{
+            this.ldapProperties.delete(key);
+            this.userForm.markAsDirty();
+        })
+    }
 }
 
 /**
@@ -134,6 +192,9 @@ export class LdapSecurityComponent extends 
EditBaseComponent<LdapConfiguration>
 export function dnValidator(): ValidatorFn {
     return (control: AbstractControl): { [key: string]: any } | null => {
         let parts = []
+        if (control.value==null) {
+            return null;
+        }
         let value = control.value.toString()
         if (value == '') {
             return null;
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/modules/shared/toast/toast.component.scss
similarity index 52%
copy from 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/model/ldap-configuration.ts
copy to 
archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/toast/toast.component.scss
index eb01950..878354a 100644
--- 
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/modules/shared/toast/toast.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * 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
@@ -15,20 +15,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+@import '~bootstrap/scss/functions';
+@import '~bootstrap/scss/variables';
+@import '~bootstrap/scss/mixins';
+@import '~bootstrap/scss/alert';
 
-export class LdapConfiguration {
-    host_name : string = "";
-    port : number = 389;
-    ssl_enabled : boolean  = false;
-    context_factory: string = "";
-    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;
-    available_context_factories : string[];
+:host {
+  margin:.5em;
+  padding:1em;
+  position:fixed;
+  right:10px;
+  top:40px;
+  z-index:1200;
+}
+
+.toast {
+  max-width: 350px;
+  font-size: 0.875rem;
+  background-clip: padding-box;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.1);
+  border-radius: 0.5rem;
+}
+
+ngb-toast.alert {
+  @extend .alert;
+}
+
+@each $color, $value in $theme-colors {
+  ngb-toast.alert-#{$color} {
+    @include alert-variant(theme-color-level($color, $alert-bg-level), 
theme-color-level($color, $alert-border-level), theme-color-level($color, 
$alert-color-level));
+  }
 }
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/toast/toast.component.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/toast/toast.component.ts
index 2873b8a..995e5d1 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/toast/toast.component.ts
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/modules/shared/toast/toast.component.ts
@@ -26,7 +26,7 @@ import {AppNotification} from "@app/model/app-notification";
   template: `
     <ngb-toast
         *ngFor="let toast of toastService.toasts"
-        [class]="toast.classname"
+        [ngClass]="toast.classname"
         [autohide]="autohide"
         [delay]="toast.delay || 5000"
         (hidden)="toastService.remove(toast); autohide=true;"
@@ -41,7 +41,7 @@ import {AppNotification} from "@app/model/app-notification";
       <ng-template #text>{{ toast.body }}</ng-template>
     </ngb-toast>
   `,
-  styles: [':host { margin:.5em; padding:1em; position:fixed; right:10px; 
top:40px; z-index:1200; }']
+  styleUrls:['./toast.component.scss']
 })
 export class ToastComponent implements OnInit {
 
@@ -53,7 +53,6 @@ export class ToastComponent implements OnInit {
   }
 
   isTemplate(toast:AppNotification) {
-    console.log("Context data: "+JSON.stringify(toast.contextData))
     return toast.body instanceof TemplateRef; }
 
 }
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts
index 8758901..244257a 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/security.service.ts
@@ -20,7 +20,7 @@ import { Injectable } from '@angular/core';
 import {ArchivaRequestService} from "@app/services/archiva-request.service";
 import {SecurityConfiguration} from "@app/model/security-configuration";
 import {Observable, throwError} from "rxjs";
-import {catchError} from "rxjs/operators";
+import {catchError, map} from "rxjs/operators";
 import {HttpErrorResponse, HttpResponse} from "@angular/common/http";
 import {BeanInformation} from "@app/model/bean-information";
 import {LdapConfiguration} from "@app/model/ldap-configuration";
@@ -42,10 +42,9 @@ export class SecurityService {
     );
   }
 
-    updateConfiguration(securityConfiguration : SecurityConfiguration) : 
Observable<HttpResponse<any>> {
-        return this.rest.executeResponseCall<any>("put", "archiva", 
"security/config", securityConfiguration).pipe(
+    updateConfiguration(securityConfiguration : SecurityConfiguration) : 
Observable<HttpResponse<SecurityConfiguration>> {
+        return this.rest.executeResponseCall<SecurityConfiguration>("put", 
"archiva", "security/config", securityConfiguration).pipe(
             catchError((error: HttpErrorResponse) => {
-                console.log("Error thrown " + typeof (error));
                 return throwError(this.rest.getTranslatedErrorResult(error));
             })
         );
@@ -69,12 +68,24 @@ export class SecurityService {
 
     getLdapConfiguration() : Observable<LdapConfiguration> {
         return this.rest.executeRestCall<LdapConfiguration>("get", "archiva", 
"security/config/ldap", null).pipe(
+            map((ldapConfig:LdapConfiguration)=>
+                new LdapConfiguration(ldapConfig)
+            ) ,
             catchError((error: HttpErrorResponse) => {
                 return throwError(this.rest.getTranslatedErrorResult(error));
             })
         );
     }
 
+    updateLdapConfiguration(ldapConfiguration : LdapConfiguration) : 
Observable<HttpResponse<LdapConfiguration>> {
+        return this.rest.executeResponseCall<LdapConfiguration>("put", 
"archiva", "security/config/ldap", ldapConfiguration).pipe(
+            catchError((error: HttpErrorResponse) => {
+                return throwError(this.rest.getTranslatedErrorResult(error));
+            })
+        );
+    }
+
+
     verifyLdapConfiguration(ldapConfig : LdapConfiguration) : 
Observable<HttpResponse<any>> {
         return this.rest.executeResponseCall<any>("post", "archiva", 
"security/config/ldap/verify", ldapConfig).pipe(
             catchError((error: HttpErrorResponse) => {
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/toast.service.ts
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/toast.service.ts
index 1b1a934..f4955ef 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/toast.service.ts
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/app/services/toast.service.ts
@@ -47,7 +47,7 @@ export class ToastService {
   }
 
   public showStandard(origin:string,textOrTpl:string|TemplateRef<any>, 
options:any={}) : void {
-    options.classname='bg-primary'
+    options.classname=['alert','alert-primary']
     if (!options.delay) {
       options.delay=8000
     }
@@ -65,7 +65,7 @@ export class ToastService {
   }
 
   public showError(origin:string,textOrTpl:string|TemplateRef<any>, 
options:any={}) : void {
-    options.classname='bg-warning'
+    options.classname=['alert','alert-danger']
     options.type='error'
     if (!options.delay) {
       options.delay=10000
@@ -84,7 +84,7 @@ export class ToastService {
   }
 
   public showSuccess(origin:string,textOrTpl:string|TemplateRef<any>, 
options:any={}) : void {
-    options.classname='bg-info'
+    options.classname=['alert','alert-info']
     options.type='success'
     if (!options.delay) {
       options.delay=8000
diff --git 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
index a10c2cf..dff49c7 100644
--- 
a/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
+++ 
b/archiva-modules/archiva-web/archiva-webapp/src/main/archiva-web/src/assets/i18n/en.json
@@ -210,6 +210,8 @@
         "explain": "Settings for the LDAP connection. These settings are only 
used, if LDAP User Manager and/or LDAP RBAC Manager is activated.",
         "check_success": "The LDAP settings have been verified successfully",
         "check_failed": "Could not connect to the LDAP server successfully",
+        "submit_success": "The LDAP settings have been updated",
+        "submit_error": "Could not update the LDAP settings: {error}",
         "attributes": {
           "host_name": "Host Name",
           "port": "Port",
@@ -222,7 +224,8 @@
           "use_role_name_as_group": "Archiva role names are LDAP group names",
           "writable": "Bind User can write to LDAP Server",
           "ssl_enabled": "Enable SSL",
-          "context_factory": "Context Factory"
+          "context_factory": "Context Factory",
+          "properties": "Properties"
 
         },
         "flags": "Flags"
@@ -253,7 +256,11 @@
       "yes": "Yes",
       "no": "No",
       "save": "Save Changes",
-      "check": "Check configuration"
+      "check": "Check configuration",
+      "checking": "Checking ...",
+      "add": "Add",
+      "key": "Key",
+      "value": "Value"
     },
     "edit": "Edit",
     "emptyContent": "No values",

Reply via email to