Si, ho capito quello che vuoi dire ma non è un granché come soluzione perché non è detto che la porta 80 sia quella del server, che la 8443 sia quella scelta in locale per l'https...
codice:MetodiApplicazione MA = new MetodiApplicazione(); if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpRes = (HttpServletResponse) response; // MA.strSum(...) è una funzione che somma delle stringhe usando uno StringBuilder. String senzaProtocollo = MA.strSum("://", httpReq.getServerName(), (httpReq.getServerPort() == 80) ? "" : ":" + httpReq.getServerPort(), httpReq.getContextPath()); try { if((request.getScheme()).equals("http")){ // MA.strSum(...) è una funzione che somma delle stringhe usando uno StringBuilder. httpRes.sendRedirect(MA.strSum("https", "://", httpReq.getServerName(), (httpReq.getServerPort() == 80) ? "" : ":" + 8443, httpReq.getContextPath())); } } catch (Exception e) { httpRes.sendRedirect(MA.strSum("http",senzaProtocollo)); } }
Più pratica in futuro...
Scusa ma che ragionamenti sono!? Se sai che ti interessa https (per i dovuti motivi come quello citato prima della geolocation), andrai PRIMA a verificare e scegliere un hosting/server che supporta https.
Non che prendi un hosting, metti un <security-constraint>, e poi dici "ohibò sono fregato, non supporta https".
Scusa eh ...
A parte che quello che hai scritto non ha proprio tantissimo senso. Non ti serve verificare che la porta della richiesta sia la 80. E non mi pare ti serva getContextPath(). I metodi che servono sono quelli citati prima, compreso il getQueryString().
Sarebbe anche utile magari il getMethod(), perché se la richiesta è un GET, il redirect ha senso. Se fosse un POST no, perché il redirect viene comunque fatto dal browser in GET.
Se pretendi che il sito sia usabile solo su https, se il client fa un POST su http normale vuol dire che o hai sbagliato tu a codificare un <form> (es. hai messo per sbaglio un url assoluto che inizia con http:// ) oppure qualcuno sta "pacioccando" con il tuo sito tentando di fare richieste a caso o per motivi dubbi ... Io farei fallire la request con un 400 (Bad Request) o un 405 (Method Not Allowed) o forse altro (sono indeciso ora ..).
Il fatto di mettere 8443 schiantato nel codice, beh, non è il massimo. Ma al limite lo si può parametrare con un sistema di "configurazione" (che comunque serve spesso in generale nelle webapp).
Ultima modifica di andbin; 26-10-2018 a 20:59
Ma certo! Su questo siamo d'accordo al 100%! E' chiaro che su un sito reale o metto il <security-constraint> o non metto nulla. Il fatto è che il mio sito gira su https in locale e http su un server (se compro un hosting lo prendo http e non https, già costano parecchio senza certificato...), vorrei evitare di avere due versioni della stessa cosa. Se poi "disgraziatamente" l'hosting mi fornisce anche l'https e io sono stato previdente evito di ricompilare, ricaricare il sito sul server, ecc...
Questa mattina mi sono svegliato presto ora non connetto più, domani ci ragiono su. Senza il filtro il sito gira in https tranquillamente. Senza filtro però se il client digita http:\\localhost:8080 accede alla versione http e ci rimane fin che non decide di ricambiare e passare ad https nuovamente. Non uso url assoluti, li evito come la peste.
Più pratica in futuro...
Il filtro va semplicemente scritto con buon senso e logica.
Innanzitutto, di base:
codice:Scheme Method Azione -------------------------------------------------------- https xxx procede normalmente con la request http == GET redirect su https http != GET fallisce la richiesta (es. status 400)
Capisco il discorso di getContextPath(): se si sta navigando con un protocollo sbagliato mando alla home e risparmio risorse.
Non capisco il discorso di getMethod(): che sia GET, POST o PUT, quando c'è http rimando alla home con protocollo https.
Non capisco il discorso di getQueryString(): che il metodo fornisca una stringa vuota oppure ciò che viene inserito nel form il discorso è sempre lo stesso (l'output deve essere su https).
Non capisco perché non testare la porta 80: se sono online la porta è 80 e non devo scrivere ":80".
Parametrizzare non capisco cosa significa.
Non sono neppure capace a far fallire la richiesta...
Mi verrebbe da risponderti in questo modo ma il codice non funziona e sarebbe qualcosa di incompleto perché non contemplo il caso di assenza di https.
Dopo cena ci ritorno sopra...codice:MetodiApplicazione MA = new MetodiApplicazione(); if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { HttpServletRequest httpReq = (HttpServletRequest) request; HttpServletResponse httpRes = (HttpServletResponse) response; // MA.strSum(...) è una funzione che somma delle stringhe usando uno StringBuilder. if((httpReq.getScheme()).equals("http")){ if((httpReq.getMethod()).equals("GET")){ if((httpReq.getQueryString()).equals("")){ // E' concesso fare GET da http ma è consentito l'utilizzo del solo protocollo https httpRes.sendRedirect(MA.strSum("https", "://", httpReq.getServerName(), (httpReq.getServerPort() == 80) ? "" : ":" + 8443)); } else{ // Non è concesso lanciare QueryString via GET da http httpRes.setStatus(400); } }else if(httpReq.getMethod().equals("POST")){ // Non è concesso fare POST da http httpRes.setStatus(400); }else if(httpReq.getMethod().equals("PUT")) { // Non è concesso fare PUT da http httpRes.setStatus(400); } } }
Quel 8443 mi sta nello stomaco...
codice:<filter-mapping> <filter-name>FiltroA</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Più pratica in futuro...
Allora: questa è solo UNA delle possibili strategie. Quella a cui pensavo io fin dall'inizio è invece quella più completa per cui se viene fatto un GET ad un url sotto http, vado a replicare TUTTO il url cambiando solo il protocollo (scheme) e la porta se necessario.
Quindi richiesto per es.:
http://localhost:8080/mywebstore/prodotti/ricerca.do?search=Camicia&sortBy=title
il filtro fa un redirect a:
https://localhost:8443/mywebstore/prodotti/ricerca.do?search=Camicia&sortBy=title
Questo richiede appunto un po' di attenzione e logica. Bisogna usare i metodi citati prima per ricomporre TUTTO il url pezzo per pezzo (perché ricordo, NON c'è un metodo che dà tutto!) cambiando solo il minimo che serve.
Un'altra strategia ancora potrebbe essere: se viene chiesto qualcosa su http, il filtro fa un forward ad una piccola JSP interna alla webapp che mostra una pagina che dice all'utente: guarda hai sbagliato url, clicca sul link qui sotto (in https ovviamente) per tornare alla home.
Quella che hai appena detto tu è una strategia ancora più drastica: rimandare subito alla home (su https) e buonanotte.
Sono strategie ... scegli TU quella che ti pare ... Punto.
Un redirect è fatto dal browser solo in GET. Se quel url della ricerca.do di esempio sopra fosse richiesto in POST, NON avrebbe senso fare il redirect a quel url in GET!
Il getQueryString() va usato solo se si vuole ricomporre TUTTO il url come ho descritto prima nella strategia più "completa". Stop, tutto qui. Punto.
Testare la porta non serve proprio a nulla. Se viene fatta una richiesta in http, NON importa se la porta è la 80 (in un ambiente reale) o la 8080 (in un ambiente di sviluppo). Lo scheme è "http", basta questo. Punto.
Se vuoi fare un redirect su https, devi sapere su quale porta il server ascolta per https. Non è una cosa scontata. In un ambiente reale è di norma quella predefinita (443). In un ambiente di sviluppo è qualcosa tipo 8443 (se non altro).
Il punto è che la API delle Servlet NON ti fornisce questa informazione. Non c'è un metodo che ti dice su quale porta il server ascolta per https. Quindi a meno di andare a spulciare la documentazione della API di Tomcat (se usi questo), o metti la porta "cablata" nel codice, oppure la metti in un file di configurazione, un <init-param> del Filter o altro.
sendError(int sc) di HttpServletResponse (sc è lo status code)
Senza ovviamente fare il chain.doFilter nel filtro.
Anche a me piace di più la prima strategia. Diciamo che rischio di perdere un sacco di tempo inutile. A livello operativo mi conviene usare <security-constraint> quando so di avere https e nulla il viceversa. Anche perché aggiornare una porta oppure diseditare un codice, operativamente, sarebbero lo stesso sbattimento.
Comunque il problema della porta 443 (server reale) non si pone perché nel link posso non scriverla.
Bisogna aggiungere un if che metta la porta quando nella url sia presente il localhost...
Più pratica in futuro...