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/finish")).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/admin/**")).hasAuthority(AuthoritiesConstants.ADMIN)
|
||||
.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.UserRepository;
|
||||
import com.oguerreiro.resilient.security.SecurityUtils;
|
||||
import com.oguerreiro.resilient.security.basic.ResilientBasicProperties;
|
||||
import com.oguerreiro.resilient.security.custom.ResilientUserDetails;
|
||||
import com.oguerreiro.resilient.service.MailService;
|
||||
import com.oguerreiro.resilient.service.UserService;
|
||||
|
@ -71,14 +72,18 @@ public class AccountResource {
|
|||
|
||||
private final RelyingPartyRegistrationRepository registrationRepository;
|
||||
|
||||
private ResilientBasicProperties resilientBasicProperties;
|
||||
|
||||
public AccountResource(UserRepository userRepository, UserService userService, MailService mailService,
|
||||
PersistentTokenRepository persistentTokenRepository,
|
||||
@Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository) {
|
||||
@Autowired(required = false) RelyingPartyRegistrationRepository registrationRepository,
|
||||
ResilientBasicProperties resilientBasicProperties) {
|
||||
this.userRepository = userRepository;
|
||||
this.userService = userService;
|
||||
this.mailService = mailService;
|
||||
this.persistentTokenRepository = persistentTokenRepository;
|
||||
this.registrationRepository = registrationRepository;
|
||||
this.resilientBasicProperties = resilientBasicProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -192,6 +197,10 @@ public class AccountResource {
|
|||
*/
|
||||
@PostMapping(path = "/account/change-password")
|
||||
public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
|
||||
if (!this.isBasicAuthActive()) {
|
||||
throw new AccountResourceException("Invalid or not allowed request");
|
||||
}
|
||||
|
||||
if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
@ -244,6 +253,10 @@ public class AccountResource {
|
|||
*/
|
||||
@PostMapping(path = "/account/reset-password/init")
|
||||
public void requestPasswordReset(@RequestBody String mail) {
|
||||
if (!this.isBasicAuthActive()) {
|
||||
throw new AccountResourceException("Invalid or not allowed request");
|
||||
}
|
||||
|
||||
Optional<User> user = userService.requestPasswordReset(mail);
|
||||
if (user.isPresent()) {
|
||||
mailService.sendPasswordResetMail(user.orElseThrow());
|
||||
|
@ -263,6 +276,10 @@ public class AccountResource {
|
|||
*/
|
||||
@PostMapping(path = "/account/reset-password/finish")
|
||||
public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
|
||||
if (!this.isBasicAuthActive()) {
|
||||
throw new AccountResourceException("Invalid or not allowed request");
|
||||
}
|
||||
|
||||
if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
@ -294,6 +311,19 @@ public class AccountResource {
|
|||
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) {
|
||||
return (StringUtils.isEmpty(password) || password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH
|
||||
|| password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH);
|
||||
|
|
|
@ -144,9 +144,11 @@ resilient:
|
|||
enabled: false
|
||||
port: 8081
|
||||
mock-idp:
|
||||
enabled: false
|
||||
enabled: true
|
||||
path: classpath:mock-idp/idp.js
|
||||
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.
|
||||
# Metadata endpoint ${base-url}/saml2/service-provider-metadata/mock-idp
|
||||
enabled: true
|
||||
|
@ -172,9 +174,9 @@ resilient:
|
|||
name: name # the user display name [OPTIONAL]
|
||||
username: urn:mace:dir:attribute-def:mail # the username, typically for authentication. Fallsback to email. [MANDATORY]
|
||||
email: email # the user email [MANDATORY]
|
||||
organization-code: organization_code # organization unit code [OPTIONAL]
|
||||
security-group-code: security_group # security group code [OPTIONAL]
|
||||
role: roles # a single role is expected [OPTIONAL]
|
||||
organization-code: # organization unit code [OPTIONAL]. Eg. "organization_code"
|
||||
security-group-code: # security group code [OPTIONAL]. Eg. "security_group"
|
||||
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
|
||||
organization-code: NOVA # default organization unit code
|
||||
security-group-code: GRP_USER # default security group code
|
||||
|
|
|
@ -18,7 +18,9 @@ logging:
|
|||
ROOT: INFO
|
||||
tech.jhipster: INFO
|
||||
com.oguerreiro.resilient: INFO
|
||||
|
||||
org.hibernate.proxy: TRACE
|
||||
org.hibernate.bytecode: TRACE
|
||||
|
||||
management:
|
||||
prometheus:
|
||||
metrics:
|
||||
|
@ -33,9 +35,9 @@ spring:
|
|||
enabled: false
|
||||
datasource:
|
||||
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
|
||||
password:
|
||||
password: root
|
||||
hikari:
|
||||
poolName: Hikari
|
||||
auto-commit: false
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Router } from '@angular/router';
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
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 { 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' });
|
||||
}
|
||||
|
||||
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> {
|
||||
return this.http.get<Account>(this.applicationConfigService.getEndpointFor('api/account'));
|
||||
}
|
||||
|
|
|
@ -12,33 +12,35 @@
|
|||
</div>
|
||||
}
|
||||
<form class="form" (ngSubmit)="login()" [formGroup]="loginForm">
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control form-control-lg"
|
||||
name="username"
|
||||
id="username"
|
||||
placeholder="{{ 'global.form.username.placeholder' | translate }}"
|
||||
formControlName="username"
|
||||
#username
|
||||
data-cy="username"
|
||||
/>
|
||||
<div *ngIf="hasBasicAuth">
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control form-control-lg"
|
||||
name="username"
|
||||
id="username"
|
||||
placeholder="{{ 'global.form.username.placeholder' | translate }}"
|
||||
formControlName="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 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>
|
||||
<p *ngIf="hasBasicAuth && saml2Endpoint">ou</p>
|
||||
<div *ngIf="saml2Endpoint">
|
||||
<p>ou</p>
|
||||
<button (click)="samlLogin()" class="btn btn-default btn-block btn-lg mb-5">Login NOVA</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -17,6 +17,7 @@ export default class LoginComponent implements OnInit, AfterViewInit {
|
|||
username = viewChild.required<ElementRef>('username');
|
||||
saml2Endpoint : string | null = null;
|
||||
authenticationError = signal(false);
|
||||
hasBasicAuth: boolean = false;
|
||||
|
||||
loginForm = new FormGroup({
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
this.accountService.hasBasicAuth().subscribe({
|
||||
next: (response: boolean) => {
|
||||
this.hasBasicAuth = response;
|
||||
},
|
||||
error: (err) => {
|
||||
console.error('Failed to fetch hasBasicAuth', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue