Nre refresh token policy applied. Request for new token, invalidates the old ones.
This commit is contained in:
parent
94dee47ab3
commit
5574d602b9
|
@ -1,13 +1,18 @@
|
|||
package eu.dnetlib.openaire.usermanagement;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
|
@ -16,7 +21,6 @@ import org.mitre.openid.connect.client.service.impl.StaticClientConfigurationSer
|
|||
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
|
||||
|
||||
|
@ -26,11 +30,13 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class PersonalTokenServlet extends HttpServlet {
|
||||
|
@ -41,6 +47,9 @@ public class PersonalTokenServlet extends HttpServlet {
|
|||
@Value("${oidc.id}")
|
||||
private String id;
|
||||
|
||||
@Value("${oidc.issuer}")
|
||||
private String issuer;
|
||||
|
||||
@Autowired
|
||||
private StaticClientConfigurationService staticClientConfigurationService;
|
||||
|
||||
|
@ -54,54 +63,65 @@ public class PersonalTokenServlet extends HttpServlet {
|
|||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
System.out.println("IN GET");
|
||||
response.setContentType("text/html");
|
||||
|
||||
OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
||||
request.getSession().setAttribute("accessToken", authentication.getAccessTokenValue());
|
||||
request.getSession().setAttribute("refreshToken", authentication.getRefreshTokenValue());
|
||||
|
||||
request.getRequestDispatcher("./personal.jsp").include(request, response);
|
||||
}
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) {
|
||||
System.out.println("IN POST");
|
||||
System.out.println(id);
|
||||
System.out.println(secret);
|
||||
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
||||
String refreshToken = authentication.getRefreshTokenValue();
|
||||
List<String> oldRefreshTokens = null;
|
||||
|
||||
try {
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
HttpPost httppost = new HttpPost("https://openaire-dev.aai-dev.grnet.gr/oidc/revoke");
|
||||
httppost.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
||||
String encoding = Base64.getEncoder().encodeToString((id.concat(":").concat(secret)).getBytes("UTF-8"));
|
||||
httppost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding);
|
||||
|
||||
List<NameValuePair> params = new ArrayList<NameValuePair>();
|
||||
params.add(new BasicNameValuePair("token", authentication.getAccessTokenValue()));
|
||||
params.add(new BasicNameValuePair("token_type_hint", "access_token"));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse resp = httpclient.execute(httppost);
|
||||
System.out.println("status " + resp.getStatusLine().getStatusCode());
|
||||
|
||||
HttpEntity entity = resp.getEntity();
|
||||
|
||||
System.out.println("REVOKE " + IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8.name()));
|
||||
oldRefreshTokens = getOldRefreshTokens(authentication.getRefreshTokenValue(), authentication.getAccessTokenValue());
|
||||
deleteOldRefreshTokens(oldRefreshTokens, authentication.getAccessTokenValue());
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error("Error deleting old refresh tokens.", e);
|
||||
//TODO should I let user know?
|
||||
}
|
||||
request.setAttribute("display_refresh_token", "display:block");
|
||||
response.sendRedirect("./personalToken");
|
||||
}
|
||||
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
logger.error("Error in Base64 encoding.", uee);
|
||||
request.getSession().setAttribute("message", "Unable to revoke your token. Please try again later");
|
||||
System.out.println("ERROR >>>> " + uee.getMessage());
|
||||
|
||||
} catch (IOException ioe) {
|
||||
logger.error("Error in Base64 encoding.", ioe);
|
||||
request.getSession().setAttribute("message", "Unable to revoke your token. Please try again later");
|
||||
System.out.println("ERROR >>>> " + ioe.getMessage());
|
||||
private void deleteOldRefreshTokens(List<String> oldRefreshTokens, String accessToken) throws IOException {
|
||||
HttpDelete httpDelete;
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
|
||||
for (String refreshTokenId:oldRefreshTokens) {
|
||||
httpDelete = new HttpDelete(issuer + "/api/tokens/refresh/" + refreshTokenId);
|
||||
httpDelete.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
|
||||
HttpResponse response = httpclient.execute(httpDelete);
|
||||
if (response.getStatusLine().getStatusCode()!=200) {
|
||||
logger.warn("Could not delete old refresh tokens." + response.getStatusLine().getStatusCode());
|
||||
System.out.println("Could not delete old refresh tokens." + response.getStatusLine().getStatusCode());//TODO should I throw exception?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getOldRefreshTokens(String currentRefreshToken, String accessToken) throws IOException {
|
||||
HttpGet httpGet = new HttpGet(issuer + "/api/tokens/refresh");
|
||||
httpGet.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
|
||||
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
String jsonResponse = IOUtils.toString(httpclient.execute(httpGet).getEntity().getContent(), StandardCharsets.UTF_8.name());
|
||||
Gson gson = new Gson();
|
||||
|
||||
List<String> oldRefreshTokens = null;
|
||||
for(RefreshToken refreshToken:gson.fromJson(jsonResponse, RefreshToken[].class)){
|
||||
if (oldRefreshTokens == null) {
|
||||
oldRefreshTokens = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (!refreshToken.getValue().equals(currentRefreshToken)) {
|
||||
oldRefreshTokens.add(refreshToken.getId()+"");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("Old refresh tokens... " + oldRefreshTokens);
|
||||
return oldRefreshTokens;
|
||||
}
|
||||
}
|
|
@ -88,14 +88,15 @@
|
|||
<h2 class="uk-h2 uk-margin-small-bottom">OpenAIRE APIs Authentication</h2>
|
||||
<div class="uk-margin-top">
|
||||
The OpenAIRE APIs can be accessed over HTTPS both by authenticated and unauthenticated requests.
|
||||
To achieve better rate limits you need to make authenticated requests. We support personal access tokens and service registration.
|
||||
For more information please read the <a href="">documentation.</a>
|
||||
To achieve <b>better rate limits</b> you need to make <b>authenticated requests</b>.
|
||||
<p><span uk-icon="icon:info"></span> For more information please read the <a href="">documentation</a>.</p>
|
||||
|
||||
</div>
|
||||
<div class="uk-grid uk-child-width-1-2@m uk-child-width-1-1@s uk-margin-top uk-text-left uk-container uk-container-small uk-margin-auto">
|
||||
<div class="uk-padding-small">
|
||||
<div class="uk-card uk-card-default uk-card-body">
|
||||
<div class=""> <a class="uk-link uk-text-large" href="./personalToken"> Personal token</a></div>
|
||||
<div>mpla mpla mpla</div>
|
||||
<div>Get access to the OpenAIRE APIs with your personal access and refresh token.</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -103,7 +104,7 @@
|
|||
<div class="uk-padding-small">
|
||||
<div class="uk-card uk-card-default uk-card-body ">
|
||||
<div class=""> <a class="uk-link uk-text-large" href="./registeredServices"> Registered Services</a></div>
|
||||
<div>mpla mpla mpla</div>
|
||||
<div>Register your services to get access to the OpenAIRE APIs.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -124,32 +124,54 @@
|
|||
<span id="server_error" class="uk-text-danger uk-text-small uk-float-left">${message}</span>
|
||||
<c:remove var="message" scope="session" />
|
||||
<form id="revoke" name="revoke" action="./personalToken" method="post">
|
||||
<a class=" uk-text-danger uk-float-right" title="Revoke access token" onClick="document.revoke.submit();"><span uk-icon="refresh" ></span></a>
|
||||
<!-- <a class=" uk-text-danger uk-float-right" title="Revoke access token" onClick="document.revoke.submit();"><span uk-icon="refresh" ></span></a> -->
|
||||
<a class=" uk-float-right uk-margin-small-left" onclick="copy('accessToken')" title="Copy access token"><span uk-icon="icon:copy"></span></a>
|
||||
<div class="uk-h5">Your personal access token is</div>
|
||||
<pre><code id="accessToken">${accessToken}</code></pre>
|
||||
<span uk-icon="icon:info"></span> Your access token is <b>valid for an hour</b>.
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<a class=" uk-text-danger uk-float-right" title="Revoke refresh token"><span uk-icon="refresh"></span></a>
|
||||
<a class=" uk-float-right uk-margin-small-left" onclick="copy('refreshToken')" title="Copy refresh token"><span uk-icon="icon: copy"></span></a>
|
||||
<div class="uk-h5">Your refresh token is</div>
|
||||
<pre><code id="refreshToken">${refreshToken}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="uk-alert-danger uk-alert uk-margin-large-top" >
|
||||
<p><b>Do not share your personal access token. Send your personal access token only over HTTPS.</b></p>
|
||||
<p>Do not share your personal access token. Send your personal access token only over HTTPS.</p>
|
||||
</div>
|
||||
<div class="uk-alert-primary uk-alert" >
|
||||
<span uk-icon="icon:info"></span> For further information on how to use the tokens please visit the <a href="">OpenAIRE API Authentication documentation</a>.
|
||||
</div>
|
||||
|
||||
<div class="uk-alert-primary uk-alert" >
|
||||
For further information on how to use the tokens please visit the <a href="">OpenAIRE API Authentication documentation</a>.
|
||||
</div>
|
||||
<div>
|
||||
<div class="uk-h5">Revoke tokens</div>
|
||||
<div>Mpla mpla mpla</div>
|
||||
<a class="uk-button uk-button-danger uk-margin-top"><span uk-icon="refresh"></span>Revoke</a>
|
||||
<!--<a class=" uk-text-danger uk-float-right" title="Revoke refresh token"><span uk-icon="refresh"></span></a>-->
|
||||
<div class="uk-h5">Do you need a refresh token?</div>
|
||||
<p>OpenAIRE refresh token <b>expires after 1 month</b> and allows you to programmatically get a new access token. </p>
|
||||
<button type="submit" class="uk-button uk-button-primary" uk-toggle="target: #refreshWarning">Get a refresh token</button>
|
||||
<div id="refreshTokenDiv" style="${display_refresh_token}">
|
||||
<c:remove var="display_refresh_token" scope="session"/>
|
||||
<div class="uk-alert-warning uk-alert" >
|
||||
Please copy your refresh token and store it confidentially. You will not be able to retrieve it.
|
||||
</div>
|
||||
<div class="uk-alert-danger uk-alert uk-margin-large-top" >
|
||||
<p>Do not share your refresh token. Send your personal access token only over HTTPS.</p>
|
||||
</div>
|
||||
<a class="uk-float-right uk-margin-small-left" onclick="copy('refreshToken')" title="Copy refresh token"><span uk-icon="icon: copy"></span></a>
|
||||
<pre><code id="refreshToken">${refreshToken}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- This is the modal -->
|
||||
<div id="refreshWarning" uk-modal>
|
||||
<div class="uk-modal-dialog uk-modal-body">
|
||||
<form id="refreshForm" action="./personalToken" method="POST">
|
||||
<h2 class="uk-modal-title">Get refresh token</h2>
|
||||
<p>In case you already have a refresh token, it will no longer be valid. Do you want to proceed?</p>
|
||||
<p class="uk-text-right">
|
||||
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button>
|
||||
<button class="uk-button uk-button-primary" type="button" onclick="submit();">Get refresh token</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- END OF CENTER SIDE -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue