Skip to content

Commit

Permalink
Issue #642
Browse files Browse the repository at this point in the history
Eseguita integrazione lavoro sulla console angular nel processo di compilazione della console.
Eseguiti test di login tramite oauth2 con la configurazione della sicurezza da file esterni.
  • Loading branch information
pintorig committed Nov 16, 2023
1 parent fe4306c commit a937787
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package it.govpay.rs.v1.authentication.oauth2.server.entrypoint;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openspcoop2.generic_project.exception.ServiceException;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.service.authentication.entrypoint.jaxrs.AbstractBasicAuthenticationEntryPoint;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.StringUtils;

import it.govpay.rs.v1.exception.CodiceEccezione;


/**
* Un {@link AuthenticationEntryPoint} estende l'implementazione {@link org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint}
* per includere una risposta nel formato GovPay nei casi non gestiti dalla procedura originale.
*
* @author Giuliano Pintori
*/
public class BearerTokenAuthenticationEntryPoint implements AuthenticationEntryPoint {

private TimeZone timeZone = TimeZone.getDefault();
private String timeZoneId = null;
public String getTimeZoneId() {
return this.timeZoneId;
}
public void setTimeZoneId(String timeZoneId) {
this.timeZoneId = timeZoneId;
this.timeZone = TimeZone.getTimeZone(timeZoneId);
}

private String realmName;

/**
* Collect error details from the provided parameters and format according to RFC
* 6750, specifically {@code error}, {@code error_description}, {@code error_uri}, and
* {@code scope}.
* @param request that resulted in an <code>AuthenticationException</code>
* @param response so that the user agent can begin authentication
* @param authException that caused the invocation
*/
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) {
HttpStatus status = HttpStatus.UNAUTHORIZED;
Map<String, String> parameters = new LinkedHashMap<>();
if (this.realmName != null) {
parameters.put("realm", this.realmName);
}
if (authException instanceof OAuth2AuthenticationException) {
OAuth2Error error = ((OAuth2AuthenticationException) authException).getError();
parameters.put("error", error.getErrorCode());
if (StringUtils.hasText(error.getDescription())) {
parameters.put("error_description", error.getDescription());
}
if (StringUtils.hasText(error.getUri())) {
parameters.put("error_uri", error.getUri());
}
if (error instanceof BearerTokenError) {
BearerTokenError bearerTokenError = (BearerTokenError) error;
if (StringUtils.hasText(bearerTokenError.getScope())) {
parameters.put("scope", bearerTokenError.getScope());
}
status = ((BearerTokenError) error).getHttpStatus();
}

String wwwAuthenticate = computeWWWAuthenticateHeaderValue(parameters);
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, wwwAuthenticate);
response.setStatus(status.value());
return;
}

// altre eccezioni
if(Utilities.existsInnerException(authException, ServiceException.class)) {
AbstractBasicAuthenticationEntryPoint.fillResponse(response, CodiceEccezione.ERRORE_INTERNO.toFaultResponse(authException), this.timeZone);
return;
}

AbstractBasicAuthenticationEntryPoint.fillResponse(response, CodiceEccezione.AUTENTICAZIONE.toFaultResponse(authException), this.timeZone);
}

/**
* Set the default realm name to use in the bearer token error response
* @param realmName
*/
public void setRealmName(String realmName) {
this.realmName = realmName;
}

private static String computeWWWAuthenticateHeaderValue(Map<String, String> parameters) {
StringBuilder wwwAuthenticate = new StringBuilder();
wwwAuthenticate.append("Bearer");
if (!parameters.isEmpty()) {
wwwAuthenticate.append(" ");
int i = 0;
for (Map.Entry<String, String> entry : parameters.entrySet()) {
wwwAuthenticate.append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
if (i != parameters.size() - 1) {
wwwAuthenticate.append(", ");
}
i++;
}
}
return wwwAuthenticate.toString();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ it.govpay.backoffice.gui.oauth2.tokenurl=
it.govpay.backoffice.gui.oauth2.codechallengemethod=
it.govpay.backoffice.gui.oauth2.scope=
it.govpay.backoffice.gui.oauth2.responsetype=
it.govpay.backoffice.gui.oauth2.boxtitle=
it.govpay.backoffice.gui.oauth2.buttonlabel=

it.govpay.backoffice.gui.export.timeout=false
it.govpay.backoffice.gui.export.limit=500
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/filters/template.filter.properties
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ it.govpay.backoffice.gui.oauth2.tokenurl=
it.govpay.backoffice.gui.oauth2.codechallengemethod=
it.govpay.backoffice.gui.oauth2.scope=
it.govpay.backoffice.gui.oauth2.responsetype=
it.govpay.backoffice.gui.oauth2.boxtitle=
it.govpay.backoffice.gui.oauth2.buttonlabel=

it.govpay.backoffice.gui.export.timeout=false
it.govpay.backoffice.gui.export.limit=500
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,28 +429,30 @@

<!-- OAUTH2_PKCE_START
<b:bean id="oauth2AuthenticationEntryPoint" class="it.govpay.rs.v1.authentication.oauth2.server.entrypoint.BearerTokenAuthenticationEntryPoint" />
<b:bean id="logoutSuccessHandlerOAuth2" class="org.openspcoop2.utils.service.authentication.handler.jaxrs.DefaultLogoutSuccessHandler" />
<b:bean id="userDetailServiceUtenzeOauth2" class="it.govpay.core.dao.autorizzazione.AutenticazioneUtenzeRegistrateDAO" >
<b:bean id="userDetailServiceUtenzeOAuth2" class="it.govpay.core.dao.autorizzazione.AutenticazioneUtenzeRegistrateDAO" >
<b:property name="apiName" value="API_BACKOFFICE" />
<b:property name="authType" value="OAUTH2" />
</b:bean>
<b:bean id="govpayJwtAuthenticationConverter" class="it.govpay.rs.v1.authentication.oauth2.server.jwt.GovPayJwtAuthenticationConverter">
<b:property name="userDetailService" ref="userDetailServiceUtenzeOauth2"/>
<b:property name="principalClaimName" value="preferred_username" />
<b:property name="userDetailService" ref="userDetailServiceUtenzeOAuth2"/>
<b:property name="principalClaimName" value="NOME_CLAIM_PRINCIPAL" />
</b:bean>
<http auto-config="false" use-expressions="true" create-session="ifRequired" pattern="/rs/oauth2/v1/**">
<http auto-config="false" pattern="/rs/oauth2/v1/info" security="none"/>
<http auto-config="false" use-expressions="true" create-session="stateless" pattern="/rs/oauth2/v1/**">
<csrf disabled="true"/>
<intercept-url pattern="/rs/oauth2/v1/info" access="permitAll" />
<intercept-url pattern="/rs/oauth2/v1/**" access="isFullyAuthenticated()" />
<intercept-url pattern="/**" access="denyAll" />
<logout logout-url="/rs/oauth2/v1/logout" success-handler-ref="logoutSuccessHandlerOAuth2" delete-cookies="JSESSIONID" invalidate-session="true" />
<oauth2-resource-server >
<oauth2-resource-server entry-point-ref="oauth2AuthenticationEntryPoint" >
<jwt jwk-set-uri="JWK_SET_URI" jwt-authentication-converter-ref="govpayJwtAuthenticationConverter" />
</oauth2-resource-server>
<headers>
<content-type-options disabled="true"/>
<frame-options disabled="true"/>
Expand Down
2 changes: 1 addition & 1 deletion wars/web-console/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<filtering>false</filtering>
<directory>src/main/angular/console/dist/</directory>
<excludes>
<exclude>assets/Config.govpay</exclude>
<exclude>assets/Config.js</exclude>
<exclude>index.html</exclude>
</excludes>
</webResource>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ const _routes: Routes = [
{ path: '**', redirectTo: UtilService.ROUTE(UtilService.URL_DASHBOARD) }
];

export const RoutingClass: ModuleWithProviders = RouterModule.forRoot(_routes,{ enableTracing: false });
export const RoutingClass: ModuleWithProviders = RouterModule.forRoot(_routes,{ enableTracing: false , useHash: true });
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class AuthViewComponent implements OnInit {
) { }

ngOnInit() {
this.state = window.localStorage.getItem(UtilService.STORAGE_VAR.TOKEN);
this.state = window.localStorage.getItem(UtilService.STORAGE_VAR.STATE);
this.codeVerifier = window.localStorage.getItem(UtilService.STORAGE_VAR.CODE_VERIFIER);
this.codeChallenge = window.localStorage.getItem(UtilService.STORAGE_VAR.CODE_CHALLENGE);

Expand All @@ -52,7 +52,7 @@ export class AuthViewComponent implements OnInit {
.append('grant_type', 'authorization_code')
.append('code', code)
.append('code_verifier', this.codeVerifier)
.append('redirect_uri', this.OAUTH2Config.REDIRECT_URI)
.append('redirect_uri', this.OAUTH2Config.REDIRECT_URI + UtilService.URL_AUTH)
.append('client_id', this.OAUTH2Config.CLIENT_ID);

const headers = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export class OAuth2LoginCardComponent implements OnInit, AfterViewInit {
.replace(/\+/g, '-')
.replace(/\//g, '_');

window.localStorage.setItem('state', state);
window.localStorage.setItem('codeVerifier', codeVerifier);
window.localStorage.setItem('codeChallenge', codeChallenge);
window.localStorage.setItem(UtilService.STORAGE_VAR.STATE, state);
window.localStorage.setItem(UtilService.STORAGE_VAR.CODE_VERIFIER, codeVerifier);
window.localStorage.setItem(UtilService.STORAGE_VAR.CODE_CHALLENGE, codeChallenge);

const params = [
'response_type='+ this.OAUTH2Config.RESPONSE_TYPE,
Expand All @@ -49,7 +49,7 @@ export class OAuth2LoginCardComponent implements OnInit, AfterViewInit {
'scope='+ this.OAUTH2Config.SCOPE,
'code_challenge=' + codeChallenge,
'code_challenge_method='+ this.OAUTH2Config.CODE_CHALLENGE_METHOD,
'redirect_uri=' + encodeURIComponent(this.OAUTH2Config.REDIRECT_URI),
'redirect_uri=' + encodeURIComponent(this.OAUTH2Config.REDIRECT_URI + UtilService.URL_AUTH),
];

window.location.href = this.OAUTH2Config.LOGIN_URL + '?' + params.join('&');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package it.govpay.web.console.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Html5RoutingFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Inizializzazione del filtro (se necessario)
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;

// Verifica se la richiesta è per un file o una directory esistente
String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
String queryString = httpRequest.getQueryString();
if (!path.contains(".")) {
// Se la richiesta non contiene un'estensione, reindirizza al percorso HTML5 compatibile con l'app Angular
String redirectPath = httpRequest.getContextPath() + "/#" + path;
if (queryString != null && !queryString.isEmpty()) {
redirectPath += "?" + queryString; // Aggiungi la query string al percorso di reindirizzamento
}
httpResponse.sendRedirect(redirectPath);
} else {
// Altrimenti, continua il normale flusso di richiesta
chain.doFilter(request, response);
}
}

@Override
public void destroy() {
// Operazioni di chiusura (se necessario)
}
}
10 changes: 10 additions & 0 deletions wars/web-console/src/main/resources/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name>govpay-web-console</display-name>

<filter>
<filter-name>Html5RoutingFilter</filter-name>
<filter-class>it.govpay.web.console.filter.Html5RoutingFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Html5RoutingFilter</filter-name>
<url-pattern>/authCallback</url-pattern>
</filter-mapping>

<error-page>
<error-code>404</error-code>
<location>/index.html</location>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@
TOKEN_URL: '${it.govpay.backoffice.gui.oauth2.tokenurl}',
CODE_CHALLENGE_METHOD: '${it.govpay.backoffice.gui.oauth2.codechallengemethod}',
SCOPE: '${it.govpay.backoffice.gui.oauth2.scope}',
RESPONSE_TYPE: '${it.govpay.backoffice.gui.oauth2.responsetype}'
RESPONSE_TYPE: '${it.govpay.backoffice.gui.oauth2.responsetype}',
BOX_TITLE: '${it.govpay.backoffice.gui.oauth2.boxtitle}',
BUTTON_LABEL: '${it.govpay.backoffice.gui.oauth2.buttonlabel}'
},
GESTIONE_PASSWORD: {
ENABLED: ${it.govpay.backoffice.gui.gestionepassword.enabled}
Expand All @@ -134,7 +136,7 @@
}
};

addScript('assets/config/app-config.govpay');
addScript('assets/config/mappingTipiEvento.govpay');
addScript('assets/config/app-config.js');
addScript('assets/config/mappingTipiEvento.js');

})(window);
2 changes: 1 addition & 1 deletion wars/web-console/src/main/webapp/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><title></title><base href="${it.govpay.backoffice.gui.baseUrl}"><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/x-icon" href="favicon.ico"><style>.web-init{border:4px solid #f3f3f3;border-top:4px solid #06f;border-radius:50%;width:40px;height:40px;animation:spin 2s linear infinite;position:fixed;top:calc(50% - 20px);left:calc(50% - 20px)}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style><script src="assets/Config.govpay"></script><link href="styles.bundle.css" rel="stylesheet"/></head><body><link-root><div class="web-init"></div></link-root><script type="text/javascript" src="inline.bundle.js"></script><script type="text/javascript" src="polyfills.bundle.js"></script><script type="text/javascript" src="scripts.bundle.js"></script><script type="text/javascript" src="vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"><title></title><base href="${it.govpay.backoffice.gui.baseUrl}"><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" type="image/x-icon" href="favicon.ico"><style>.web-init{border:4px solid #f3f3f3;border-top:4px solid #06f;border-radius:50%;width:40px;height:40px;animation:spin 2s linear infinite;position:fixed;top:calc(50% - 20px);left:calc(50% - 20px)}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}</style><script src="assets/Config.js"></script><link href="styles.bundle.css" rel="stylesheet"/></head><body><link-root><div class="web-init"></div></link-root><script type="text/javascript" src="inline.bundle.js"></script><script type="text/javascript" src="polyfills.bundle.js"></script><script type="text/javascript" src="scripts.bundle.js"></script><script type="text/javascript" src="vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body></html>

0 comments on commit a937787

Please sign in to comment.