Configurar a possibilidade de inativar autenticação por user+password
Some checks failed
Release / release (push) Failing after 10m3s
Some checks failed
Release / release (push) Failing after 10m3s
fixes #13
This commit is contained in:
parent
93193c6165
commit
c3eb88972c
7 changed files with 89 additions and 34 deletions
|
@ -219,6 +219,7 @@ public class SecurityConfiguration {
|
||||||
.requestMatchers(mvc.pattern("/api/account/reset-password/init")).permitAll()
|
.requestMatchers(mvc.pattern("/api/account/reset-password/init")).permitAll()
|
||||||
.requestMatchers(mvc.pattern("/api/account/reset-password/finish")).permitAll()
|
.requestMatchers(mvc.pattern("/api/account/reset-password/finish")).permitAll()
|
||||||
.requestMatchers(mvc.pattern("/api/account/saml2-endpoint")).permitAll()
|
.requestMatchers(mvc.pattern("/api/account/saml2-endpoint")).permitAll()
|
||||||
|
.requestMatchers(mvc.pattern("/api/account/has-basic-auth")).permitAll()
|
||||||
.requestMatchers(mvc.pattern("/api/home/page")).permitAll()
|
.requestMatchers(mvc.pattern("/api/home/page")).permitAll()
|
||||||
.requestMatchers(mvc.pattern("/api/admin/**")).hasAuthority(AuthoritiesConstants.ADMIN)
|
.requestMatchers(mvc.pattern("/api/admin/**")).hasAuthority(AuthoritiesConstants.ADMIN)
|
||||||
.requestMatchers(mvc.pattern("/api/**")).authenticated()
|
.requestMatchers(mvc.pattern("/api/**")).authenticated()
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.oguerreiro.resilient.domain.User;
|
||||||
import com.oguerreiro.resilient.repository.PersistentTokenRepository;
|
import com.oguerreiro.resilient.repository.PersistentTokenRepository;
|
||||||
import com.oguerreiro.resilient.repository.UserRepository;
|
import com.oguerreiro.resilient.repository.UserRepository;
|
||||||
import com.oguerreiro.resilient.security.SecurityUtils;
|
import com.oguerreiro.resilient.security.SecurityUtils;
|
||||||
|
import com.oguerreiro.resilient.security.basic.ResilientBasicProperties;
|
||||||
import com.oguerreiro.resilient.security.custom.ResilientUserDetails;
|
import com.oguerreiro.resilient.security.custom.ResilientUserDetails;
|
||||||
import com.oguerreiro.resilient.service.MailService;
|
import com.oguerreiro.resilient.service.MailService;
|
||||||
import com.oguerreiro.resilient.service.UserService;
|
import com.oguerreiro.resilient.service.UserService;
|
||||||
|
@ -71,14 +72,18 @@ public class AccountResource {
|
||||||
|
|
||||||
private final RelyingPartyRegistrationRepository registrationRepository;
|
private final RelyingPartyRegistrationRepository registrationRepository;
|
||||||
|
|
||||||
|
private ResilientBasicProperties resilientBasicProperties;
|
||||||
|
|
||||||
public AccountResource(UserRepository userRepository, UserService userService, MailService mailService,
|
public AccountResource(UserRepository userRepository, UserService userService, MailService mailService,
|
||||||
PersistentTokenRepository persistentTokenRepository,
|
PersistentTokenRepository persistentTokenRepository,
|
||||||
@Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository) {
|
@Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository,
|
||||||
|
ResilientBasicProperties resilientBasicProperties) {
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.mailService = mailService;
|
this.mailService = mailService;
|
||||||
this.persistentTokenRepository = persistentTokenRepository;
|
this.persistentTokenRepository = persistentTokenRepository;
|
||||||
this.registrationRepository = registrationRepository;
|
this.registrationRepository = registrationRepository;
|
||||||
|
this.resilientBasicProperties = resilientBasicProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,6 +197,10 @@ public class AccountResource {
|
||||||
*/
|
*/
|
||||||
@PostMapping(path = "/account/change-password")
|
@PostMapping(path = "/account/change-password")
|
||||||
public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
|
public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
|
||||||
|
if (!this.isBasicAuthActive()) {
|
||||||
|
throw new AccountResourceException("Invalid or not allowed request");
|
||||||
|
}
|
||||||
|
|
||||||
if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) {
|
if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) {
|
||||||
throw new InvalidPasswordException();
|
throw new InvalidPasswordException();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +253,10 @@ public class AccountResource {
|
||||||
*/
|
*/
|
||||||
@PostMapping(path = "/account/reset-password/init")
|
@PostMapping(path = "/account/reset-password/init")
|
||||||
public void requestPasswordReset(@RequestBody String mail) {
|
public void requestPasswordReset(@RequestBody String mail) {
|
||||||
|
if (!this.isBasicAuthActive()) {
|
||||||
|
throw new AccountResourceException("Invalid or not allowed request");
|
||||||
|
}
|
||||||
|
|
||||||
Optional<User> user = userService.requestPasswordReset(mail);
|
Optional<User> user = userService.requestPasswordReset(mail);
|
||||||
if (user.isPresent()) {
|
if (user.isPresent()) {
|
||||||
mailService.sendPasswordResetMail(user.orElseThrow());
|
mailService.sendPasswordResetMail(user.orElseThrow());
|
||||||
|
@ -263,6 +276,10 @@ public class AccountResource {
|
||||||
*/
|
*/
|
||||||
@PostMapping(path = "/account/reset-password/finish")
|
@PostMapping(path = "/account/reset-password/finish")
|
||||||
public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
|
public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
|
||||||
|
if (!this.isBasicAuthActive()) {
|
||||||
|
throw new AccountResourceException("Invalid or not allowed request");
|
||||||
|
}
|
||||||
|
|
||||||
if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) {
|
if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) {
|
||||||
throw new InvalidPasswordException();
|
throw new InvalidPasswordException();
|
||||||
}
|
}
|
||||||
|
@ -294,6 +311,19 @@ public class AccountResource {
|
||||||
return ids.get(0);
|
return ids.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping(path = "/account/has-basic-auth")
|
||||||
|
public Boolean hasBasicAuthentication() {
|
||||||
|
return this.isBasicAuthActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBasicAuthActive() {
|
||||||
|
if (this.resilientBasicProperties != null && this.resilientBasicProperties.isEnabled()) {
|
||||||
|
return this.resilientBasicProperties.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isPasswordLengthInvalid(String password) {
|
private static boolean isPasswordLengthInvalid(String password) {
|
||||||
return (StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH
|
return (StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH
|
||||||
|| password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH);
|
|| password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH);
|
||||||
|
|
|
@ -144,9 +144,11 @@ resilient:
|
||||||
enabled: false
|
enabled: false
|
||||||
port: 8081
|
port: 8081
|
||||||
mock-idp:
|
mock-idp:
|
||||||
enabled: false
|
enabled: true
|
||||||
path: classpath:mock-idp/idp.js
|
path: classpath:mock-idp/idp.js
|
||||||
security:
|
security:
|
||||||
|
basic: # ADDED to config the formLogin (user+password). This allows for the DISABLE of basic authentication
|
||||||
|
enabled: true
|
||||||
saml2: # ADDED to support SAMLv2 authentication to IDP.
|
saml2: # ADDED to support SAMLv2 authentication to IDP.
|
||||||
# Metadata endpoint ${base-url}/saml2/service-provider-metadata/mock-idp
|
# Metadata endpoint ${base-url}/saml2/service-provider-metadata/mock-idp
|
||||||
enabled: true
|
enabled: true
|
||||||
|
@ -172,9 +174,9 @@ resilient:
|
||||||
name: name # the user display name [OPTIONAL]
|
name: name # the user display name [OPTIONAL]
|
||||||
username: urn:mace:dir:attribute-def:mail # the username, typically for authentication. Fallsback to email. [MANDATORY]
|
username: urn:mace:dir:attribute-def:mail # the username, typically for authentication. Fallsback to email. [MANDATORY]
|
||||||
email: email # the user email [MANDATORY]
|
email: email # the user email [MANDATORY]
|
||||||
organization-code: organization_code # organization unit code [OPTIONAL]
|
organization-code: # organization unit code [OPTIONAL]. Eg. "organization_code"
|
||||||
security-group-code: security_group # security group code [OPTIONAL]
|
security-group-code: # security group code [OPTIONAL]. Eg. "security_group"
|
||||||
role: roles # a single role is expected [OPTIONAL]
|
role: # a single role is expected [OPTIONAL]. Eg. "roles"
|
||||||
defaults: # For some attributes defaults can be given. This will be used if SAML2 response doesn't have them
|
defaults: # For some attributes defaults can be given. This will be used if SAML2 response doesn't have them
|
||||||
organization-code: NOVA # default organization unit code
|
organization-code: NOVA # default organization unit code
|
||||||
security-group-code: GRP_USER # default security group code
|
security-group-code: GRP_USER # default security group code
|
||||||
|
|
|
@ -18,7 +18,9 @@ logging:
|
||||||
ROOT: INFO
|
ROOT: INFO
|
||||||
tech.jhipster: INFO
|
tech.jhipster: INFO
|
||||||
com.oguerreiro.resilient: INFO
|
com.oguerreiro.resilient: INFO
|
||||||
|
org.hibernate.proxy: TRACE
|
||||||
|
org.hibernate.bytecode: TRACE
|
||||||
|
|
||||||
management:
|
management:
|
||||||
prometheus:
|
prometheus:
|
||||||
metrics:
|
metrics:
|
||||||
|
@ -33,9 +35,9 @@ spring:
|
||||||
enabled: false
|
enabled: false
|
||||||
datasource:
|
datasource:
|
||||||
type: com.zaxxer.hikari.HikariDataSource
|
type: com.zaxxer.hikari.HikariDataSource
|
||||||
url: jdbc:mysql://localhost:3306/resilient?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true
|
url: jdbc:mysql://localhost:3306/resilient_resilient?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&createDatabaseIfNotExist=true
|
||||||
username: root
|
username: root
|
||||||
password:
|
password: root
|
||||||
hikari:
|
hikari:
|
||||||
poolName: Hikari
|
poolName: Hikari
|
||||||
auto-commit: false
|
auto-commit: false
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Router } from '@angular/router';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Observable, ReplaySubject, of } from 'rxjs';
|
import { Observable, ReplaySubject, of } from 'rxjs';
|
||||||
import { shareReplay, tap, catchError } from 'rxjs/operators';
|
import { shareReplay, tap, catchError, map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { StateStorageService } from 'app/core/auth/state-storage.service';
|
import { StateStorageService } from 'app/core/auth/state-storage.service';
|
||||||
import { Account } from 'app/core/auth/account.model';
|
import { Account } from 'app/core/auth/account.model';
|
||||||
|
@ -95,6 +95,14 @@ export class AccountService {
|
||||||
return this.http.get(this.applicationConfigService.getEndpointFor('api/account/saml2-endpoint'), { responseType: 'text' as 'text' });
|
return this.http.get(this.applicationConfigService.getEndpointFor('api/account/saml2-endpoint'), { responseType: 'text' as 'text' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasBasicAuth(): Observable<boolean> {
|
||||||
|
return this.http.get(
|
||||||
|
this.applicationConfigService.getEndpointFor('api/account/has-basic-auth'), { responseType: 'text' as 'text' }
|
||||||
|
).pipe(
|
||||||
|
map(response => response === 'true')
|
||||||
|
);;
|
||||||
|
}
|
||||||
|
|
||||||
private fetch(): Observable<Account> {
|
private fetch(): Observable<Account> {
|
||||||
return this.http.get<Account>(this.applicationConfigService.getEndpointFor('api/account'));
|
return this.http.get<Account>(this.applicationConfigService.getEndpointFor('api/account'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,33 +12,35 @@
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<form class="form" (ngSubmit)="login()" [formGroup]="loginForm">
|
<form class="form" (ngSubmit)="login()" [formGroup]="loginForm">
|
||||||
<div class="form-group">
|
<div *ngIf="hasBasicAuth">
|
||||||
<input
|
<div class="form-group">
|
||||||
type="text"
|
<input
|
||||||
class="form-control form-control-lg"
|
type="text"
|
||||||
name="username"
|
class="form-control form-control-lg"
|
||||||
id="username"
|
name="username"
|
||||||
placeholder="{{ 'global.form.username.placeholder' | translate }}"
|
id="username"
|
||||||
formControlName="username"
|
placeholder="{{ 'global.form.username.placeholder' | translate }}"
|
||||||
#username
|
formControlName="username"
|
||||||
data-cy="username"
|
#username
|
||||||
/>
|
data-cy="username"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-0">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="form-control form-control-lg"
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
placeholder="{{ 'login.form.password.placeholder' | translate }}"
|
||||||
|
formControlName="password"
|
||||||
|
data-cy="password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p class="text-right"><a routerLink="/account/reset/request" data-cy="forgetYourPasswordSelector" jhiTranslate="login.password.forgot">Esqueci-me da palavra passe</a></p>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block btn-lg mb-3" data-cy="submit" jhiTranslate="login.form.button">Entrar</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mb-0">
|
<p *ngIf="hasBasicAuth && saml2Endpoint">ou</p>
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
class="form-control form-control-lg"
|
|
||||||
name="password"
|
|
||||||
id="password"
|
|
||||||
placeholder="{{ 'login.form.password.placeholder' | translate }}"
|
|
||||||
formControlName="password"
|
|
||||||
data-cy="password"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p class="text-right"><a routerLink="/account/reset/request" data-cy="forgetYourPasswordSelector" jhiTranslate="login.password.forgot">Esqueci-me da palavra passe</a></p>
|
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-lg mb-3" data-cy="submit" jhiTranslate="login.form.button">Entrar</button>
|
|
||||||
<div *ngIf="saml2Endpoint">
|
<div *ngIf="saml2Endpoint">
|
||||||
<p>ou</p>
|
|
||||||
<button (click)="samlLogin()" class="btn btn-default btn-block btn-lg mb-5">Login NOVA</button>
|
<button (click)="samlLogin()" class="btn btn-default btn-block btn-lg mb-5">Login NOVA</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -17,6 +17,7 @@ export default class LoginComponent implements OnInit, AfterViewInit {
|
||||||
username = viewChild.required<ElementRef>('username');
|
username = viewChild.required<ElementRef>('username');
|
||||||
saml2Endpoint : string | null = null;
|
saml2Endpoint : string | null = null;
|
||||||
authenticationError = signal(false);
|
authenticationError = signal(false);
|
||||||
|
hasBasicAuth: boolean = false;
|
||||||
|
|
||||||
loginForm = new FormGroup({
|
loginForm = new FormGroup({
|
||||||
username: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
|
username: new FormControl('', { nonNullable: true, validators: [Validators.required] }),
|
||||||
|
@ -44,6 +45,15 @@ export default class LoginComponent implements OnInit, AfterViewInit {
|
||||||
console.error('Failed to fetch SAML2 endpoint', err);
|
console.error('Failed to fetch SAML2 endpoint', err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.accountService.hasBasicAuth().subscribe({
|
||||||
|
next: (response: boolean) => {
|
||||||
|
this.hasBasicAuth = response;
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Failed to fetch hasBasicAuth', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue