Skip to content

Commit 7ac0ee9

Browse files
Andrea Barbassoatarix83
authored andcommitted
Merged in task/dspace-cris-2024_02_x/DSC-2401 (pull request DSpace#3348)
[DSC-2401] add options to disable the standard login Approved-by: Giuseppe Digilio
2 parents eb9d5ab + d63c967 commit 7ac0ee9

7 files changed

Lines changed: 112 additions & 15 deletions

File tree

config/config.example.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ auth:
135135
# If the rest token expires in less than this amount of time, it will be refreshed automatically.
136136
# This is independent from the idle warning.
137137
timeLeftBeforeTokenRefresh: 120000 # 2 minutes
138+
# Standard login enabled
139+
disableStandardLogin: false
138140

139141
# Form settings
140142
form:

src/app/app-routes.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
RouterConfigOptions,
55
} from '@angular/router';
66

7+
import { environment } from '../environments/environment';
78
import { NOTIFICATIONS_MODULE_PATH } from './admin/admin-routing-paths';
89
import {
910
ACCESS_CONTROL_MODULE_PATH,
@@ -171,10 +172,20 @@ export const APP_ROUTES: Route[] = [
171172
providers: [provideSuggestionNotificationsState()],
172173
canActivate: [authenticatedGuard, endUserAgreementCurrentUserGuard],
173174
},
175+
{
176+
path: 'standard-login',
177+
loadChildren: () => import('./login-page/login-page-routes').then((m) => m.ROUTES),
178+
data: {
179+
isBackDoor: true,
180+
},
181+
},
174182
{
175183
path: 'login',
176-
loadChildren: () => import('./login-page/login-page-routes')
177-
.then((m) => m.ROUTES),
184+
loadChildren: () => import('./login-page/login-page-routes').then((m) => m.ROUTES),
185+
data: {
186+
isBackDoor: false,
187+
},
188+
canMatch: [() => !environment.auth.disableStandardLogin],
178189
},
179190
{
180191
path: 'logout',

src/app/shared/log-in/log-in.component.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { StoreModule } from '@ngrx/store';
1919
import { provideMockStore } from '@ngrx/store/testing';
2020
import { TranslateModule } from '@ngx-translate/core';
2121
import { of } from 'rxjs';
22+
import { AuthMethodType } from 'src/app/core/auth/models/auth.method-type';
2223

2324
import { authReducer } from '../../core/auth/auth.reducer';
2425
import { AuthService } from '../../core/auth/auth.service';
@@ -140,6 +141,59 @@ describe('LogInComponent', () => {
140141
expect(loginContainers.length).toBe(2);
141142

142143
});
144+
145+
it('returns only password method when backdoor is enabled', () => {
146+
const authMethods = [
147+
{ authMethodType: AuthMethodType.Password, position: 1 },
148+
{ authMethodType: AuthMethodType.Ip, position: 2 },
149+
{ authMethodType: AuthMethodType.Shibboleth, position: 3 },
150+
];
151+
const isBackdoor = true;
152+
component.excludedAuthMethod = undefined;
153+
const result = component.filterAndSortAuthMethods(authMethods, isBackdoor);
154+
expect(result).toEqual([{ authMethodType: AuthMethodType.Password, position: 1 }]);
155+
});
156+
157+
it('excludes password method when standard login is disabled', () => {
158+
const authMethods = [
159+
{ authMethodType: AuthMethodType.Password, position: 1 },
160+
{ authMethodType: AuthMethodType.Shibboleth, position: 2 },
161+
];
162+
component.excludedAuthMethod = undefined;
163+
const result = component.filterAndSortAuthMethods(authMethods, false, true);
164+
expect(result).toEqual([
165+
{ authMethodType: AuthMethodType.Shibboleth, position: 2 },
166+
]);
167+
});
168+
169+
it('excludes methods based on excludedAuthMethod input', () => {
170+
const authMethods = [
171+
{ authMethodType: AuthMethodType.Password, position: 1 },
172+
{ authMethodType: AuthMethodType.Ip, position: 2 },
173+
{ authMethodType: AuthMethodType.Shibboleth, position: 3 },
174+
];
175+
const isBackdoor = false;
176+
component.excludedAuthMethod = AuthMethodType.Ip;
177+
const result = component.filterAndSortAuthMethods(authMethods, isBackdoor);
178+
expect(result).toEqual([
179+
{ authMethodType: AuthMethodType.Password, position: 1 },
180+
{ authMethodType: AuthMethodType.Shibboleth, position: 3 },
181+
]);
182+
});
183+
184+
it('sorts methods by position', () => {
185+
const authMethods = [
186+
{ authMethodType: AuthMethodType.Password, position: 2 },
187+
{ authMethodType: AuthMethodType.Shibboleth, position: 1 },
188+
];
189+
const isBackdoor = false;
190+
component.excludedAuthMethod = undefined;
191+
const result = component.filterAndSortAuthMethods(authMethods, isBackdoor);
192+
expect(result).toEqual([
193+
{ authMethodType: AuthMethodType.Shibboleth, position: 1 },
194+
{ authMethodType: AuthMethodType.Password, position: 2 },
195+
]);
196+
});
143197
});
144198

145199
});

src/app/shared/log-in/log-in.component.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ import {
1010
OnDestroy,
1111
OnInit,
1212
} from '@angular/core';
13-
import { RouterLink } from '@angular/router';
13+
import {
14+
ActivatedRoute,
15+
RouterLink,
16+
} from '@angular/router';
1417
import {
1518
select,
1619
Store,
1720
} from '@ngrx/store';
1821
import { TranslateModule } from '@ngx-translate/core';
1922
import uniqBy from 'lodash/uniqBy';
2023
import {
21-
combineLatest,
24+
combineLatestWith,
2225
map,
2326
Observable,
2427
Subscription,
@@ -28,6 +31,7 @@ import {
2831
shareReplay,
2932
} from 'rxjs/operators';
3033

34+
import { environment } from '../../../environments/environment';
3135
import {
3236
getForgotPasswordRoute,
3337
getRegisterRoute,
@@ -116,19 +120,20 @@ export class LogInComponent implements OnInit, OnDestroy {
116120

117121
constructor(private store: Store<CoreState>,
118122
private authService: AuthService,
123+
private route: ActivatedRoute,
119124
protected authorizationService: AuthorizationDataService,
120125
) {
121126
}
122127

123128
ngOnInit(): void {
124129
this.authMethods = this.store.pipe(
125130
select(getAuthenticationMethods),
126-
map((methods: AuthMethod[]) => methods
127-
// ignore the given auth method if it should be excluded
128-
.filter((authMethod: AuthMethod) => authMethod.authMethodType !== this.excludedAuthMethod)
129-
.filter((authMethod: AuthMethod) => rendersAuthMethodType(authMethod.authMethodType) !== undefined)
130-
.sort((method1: AuthMethod, method2: AuthMethod) => method1.position - method2.position),
131-
),
131+
combineLatestWith(
132+
this.route.data.pipe(
133+
filter(routeData => !!routeData),
134+
map(data => data.isBackDoor),
135+
)),
136+
map(([methods, isBackdoor]) => this.filterAndSortAuthMethods(methods, isBackdoor, environment.auth.disableStandardLogin)),
132137
// ignore the ip authentication method when it's returned by the backend
133138
map((authMethods: AuthMethod[]) => uniqBy(authMethods.filter(a => a.authMethodType !== AuthMethodType.Ip), 'authMethodType')),
134139
);
@@ -149,11 +154,31 @@ export class LogInComponent implements OnInit, OnDestroy {
149154
this.canRegister$ = this.authorizationService.isAuthorized(FeatureID.EPersonRegistration);
150155

151156
this.canForgot$ = this.authorizationService.isAuthorized(FeatureID.EPersonForgotPassword).pipe(shareReplay({ refCount: false, bufferSize: 1 }));
152-
this.canShowDivider$ = combineLatest([this.canRegister$, this.canForgot$])
153-
.pipe(
154-
map(([canRegister, canForgot]) => canRegister || canForgot),
155-
filter(Boolean),
156-
);
157+
this.canShowDivider$ = this.canRegister$.pipe(
158+
combineLatestWith(this.canForgot$)
159+
,
160+
map(([canRegister, canForgot]) => canRegister || canForgot),
161+
filter(Boolean),
162+
);
163+
}
164+
165+
filterAndSortAuthMethods(authMethods: AuthMethod[], isBackdoor: boolean, isStandardLoginDisabled = false): AuthMethod[] {
166+
return authMethods.filter((authMethod: AuthMethod) => {
167+
const methodComparison = (authM) => {
168+
if (isBackdoor) {
169+
return authM.authMethodType === AuthMethodType.Password;
170+
}
171+
if (isStandardLoginDisabled) {
172+
return authM.authMethodType !== AuthMethodType.Password;
173+
}
174+
return true;
175+
176+
};
177+
return methodComparison(authMethod) &&
178+
authMethod.authMethodType !== this.excludedAuthMethod &&
179+
rendersAuthMethodType(authMethod.authMethodType) !== undefined;
180+
},
181+
).sort((method1: AuthMethod, method2: AuthMethod) => method1.position - method2.position);
157182
}
158183

159184
getRegisterRoute() {

src/config/auth-config.interfaces.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ export interface AuthConfig extends Config {
2020
// This is independent from the idle warning.
2121
timeLeftBeforeTokenRefresh: number;
2222
};
23+
24+
// Whether the standard login form should be enabled.
25+
disableStandardLogin?: boolean;
2326
}

src/config/default-app-config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ export class DefaultAppConfig implements AppConfig {
146146
// This is independent from the idle warning.
147147
timeLeftBeforeTokenRefresh: 2 * 60 * 1000, // 2 minutes
148148
},
149+
disableStandardLogin: false, // Enable the standard login form
149150
};
150151

151152
// Form settings

src/environments/environment.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export const environment: BuildConfig = {
9797
// This is independent from the idle warning.
9898
timeLeftBeforeTokenRefresh: 20000, // 20 sec
9999
},
100+
disableStandardLogin: false,
100101
},
101102

102103
// Form settings

0 commit comments

Comments
 (0)