Revision 59621
Added by Katerina Iatropoulou over 3 years ago
modules/dnet-openaire-users/trunk/src/main/java/eu/dnetlib/openaire/usermanagement/PersonalTokenServlet.java | ||
---|---|---|
1 | 1 |
package eu.dnetlib.openaire.usermanagement; |
2 | 2 |
|
3 |
import com.google.gson.Gson; |
|
4 |
import com.google.gson.GsonBuilder; |
|
5 |
import com.google.gson.reflect.TypeToken; |
|
3 | 6 |
import org.apache.commons.io.IOUtils; |
4 | 7 |
import org.apache.http.HttpEntity; |
5 | 8 |
import org.apache.http.HttpHeaders; |
6 | 9 |
import org.apache.http.HttpResponse; |
7 | 10 |
import org.apache.http.NameValuePair; |
8 | 11 |
import org.apache.http.client.entity.UrlEncodedFormEntity; |
12 |
import org.apache.http.client.methods.CloseableHttpResponse; |
|
13 |
import org.apache.http.client.methods.HttpDelete; |
|
14 |
import org.apache.http.client.methods.HttpGet; |
|
9 | 15 |
import org.apache.http.client.methods.HttpPost; |
10 |
import org.apache.http.entity.StringEntity; |
|
11 | 16 |
import org.apache.http.impl.client.CloseableHttpClient; |
12 | 17 |
import org.apache.http.impl.client.HttpClients; |
13 | 18 |
import org.apache.http.message.BasicNameValuePair; |
... | ... | |
16 | 21 |
import org.mitre.openid.connect.model.OIDCAuthenticationToken; |
17 | 22 |
import org.springframework.beans.factory.annotation.Autowired; |
18 | 23 |
import org.springframework.beans.factory.annotation.Value; |
19 |
import org.springframework.security.access.prepost.PreAuthorize; |
|
20 | 24 |
import org.springframework.security.core.context.SecurityContextHolder; |
21 | 25 |
import org.springframework.web.context.support.SpringBeanAutowiringSupport; |
22 | 26 |
|
... | ... | |
26 | 30 |
import javax.servlet.http.HttpServletRequest; |
27 | 31 |
import javax.servlet.http.HttpServletResponse; |
28 | 32 |
import java.io.IOException; |
33 |
import java.io.Serializable; |
|
29 | 34 |
import java.io.UnsupportedEncodingException; |
35 |
import java.lang.reflect.Array; |
|
36 |
import java.lang.reflect.Type; |
|
37 |
import java.math.BigDecimal; |
|
30 | 38 |
import java.nio.charset.StandardCharsets; |
31 |
import java.util.ArrayList; |
|
32 |
import java.util.Base64; |
|
33 |
import java.util.List; |
|
39 |
import java.util.*; |
|
34 | 40 |
|
35 | 41 |
|
36 | 42 |
public class PersonalTokenServlet extends HttpServlet { |
... | ... | |
41 | 47 |
@Value("${oidc.id}") |
42 | 48 |
private String id; |
43 | 49 |
|
50 |
@Value("${oidc.issuer}") |
|
51 |
private String issuer; |
|
52 |
|
|
44 | 53 |
@Autowired |
45 | 54 |
private StaticClientConfigurationService staticClientConfigurationService; |
46 | 55 |
|
... | ... | |
54 | 63 |
|
55 | 64 |
public void doGet(HttpServletRequest request, HttpServletResponse response) |
56 | 65 |
throws ServletException, IOException { |
57 |
System.out.println("IN GET"); |
|
58 | 66 |
response.setContentType("text/html"); |
59 |
|
|
60 | 67 |
OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); |
61 | 68 |
request.getSession().setAttribute("accessToken", authentication.getAccessTokenValue()); |
62 | 69 |
request.getSession().setAttribute("refreshToken", authentication.getRefreshTokenValue()); |
63 |
|
|
64 | 70 |
request.getRequestDispatcher("./personal.jsp").include(request, response); |
65 | 71 |
} |
66 | 72 |
|
67 |
public void doPost(HttpServletRequest request, HttpServletResponse response) { |
|
68 |
System.out.println("IN POST"); |
|
69 |
System.out.println(id); |
|
70 |
System.out.println(secret); |
|
71 |
|
|
73 |
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { |
|
72 | 74 |
OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); |
75 |
String refreshToken = authentication.getRefreshTokenValue(); |
|
76 |
List<String> oldRefreshTokens = null; |
|
73 | 77 |
|
74 | 78 |
try { |
75 |
CloseableHttpClient httpclient = HttpClients.createDefault(); |
|
76 |
HttpPost httppost = new HttpPost("https://openaire-dev.aai-dev.grnet.gr/oidc/revoke"); |
|
77 |
httppost.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded"); |
|
78 |
String encoding = Base64.getEncoder().encodeToString((id.concat(":").concat(secret)).getBytes("UTF-8")); |
|
79 |
httppost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding); |
|
79 |
oldRefreshTokens = getOldRefreshTokens(authentication.getRefreshTokenValue(), authentication.getAccessTokenValue()); |
|
80 |
deleteOldRefreshTokens(oldRefreshTokens, authentication.getAccessTokenValue()); |
|
80 | 81 |
|
81 |
List<NameValuePair> params = new ArrayList<NameValuePair>(); |
|
82 |
params.add(new BasicNameValuePair("token", authentication.getAccessTokenValue())); |
|
83 |
params.add(new BasicNameValuePair("token_type_hint", "access_token")); |
|
84 |
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); |
|
82 |
} catch (IOException e) { |
|
83 |
logger.error("Error deleting old refresh tokens.", e); |
|
84 |
//TODO should I let user know? |
|
85 |
} |
|
86 |
request.setAttribute("display_refresh_token", "display:block"); |
|
87 |
response.sendRedirect("./personalToken"); |
|
88 |
} |
|
85 | 89 |
|
86 |
HttpResponse resp = httpclient.execute(httppost); |
|
87 |
System.out.println("status " + resp.getStatusLine().getStatusCode()); |
|
90 |
private void deleteOldRefreshTokens(List<String> oldRefreshTokens, String accessToken) throws IOException { |
|
91 |
HttpDelete httpDelete; |
|
92 |
CloseableHttpClient httpclient = HttpClients.createDefault(); |
|
88 | 93 |
|
89 |
HttpEntity entity = resp.getEntity(); |
|
94 |
for (String refreshTokenId:oldRefreshTokens) { |
|
95 |
httpDelete = new HttpDelete(issuer + "/api/tokens/refresh/" + refreshTokenId); |
|
96 |
httpDelete.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); |
|
97 |
HttpResponse response = httpclient.execute(httpDelete); |
|
98 |
if (response.getStatusLine().getStatusCode()!=200) { |
|
99 |
logger.warn("Could not delete old refresh tokens." + response.getStatusLine().getStatusCode()); |
|
100 |
System.out.println("Could not delete old refresh tokens." + response.getStatusLine().getStatusCode());//TODO should I throw exception? |
|
101 |
} |
|
102 |
} |
|
103 |
} |
|
90 | 104 |
|
91 |
System.out.println("REVOKE " + IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8.name())); |
|
105 |
private List<String> getOldRefreshTokens(String currentRefreshToken, String accessToken) throws IOException { |
|
106 |
HttpGet httpGet = new HttpGet(issuer + "/api/tokens/refresh"); |
|
107 |
httpGet.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); |
|
92 | 108 |
|
93 |
response.sendRedirect("./personalToken"); |
|
109 |
CloseableHttpClient httpclient = HttpClients.createDefault(); |
|
110 |
String jsonResponse = IOUtils.toString(httpclient.execute(httpGet).getEntity().getContent(), StandardCharsets.UTF_8.name()); |
|
111 |
Gson gson = new Gson(); |
|
94 | 112 |
|
95 |
} catch (UnsupportedEncodingException uee) { |
|
96 |
logger.error("Error in Base64 encoding.", uee); |
|
97 |
request.getSession().setAttribute("message", "Unable to revoke your token. Please try again later"); |
|
98 |
System.out.println("ERROR >>>> " + uee.getMessage()); |
|
113 |
List<String> oldRefreshTokens = null; |
|
114 |
for(RefreshToken refreshToken:gson.fromJson(jsonResponse, RefreshToken[].class)){ |
|
115 |
if (oldRefreshTokens == null) { |
|
116 |
oldRefreshTokens = new ArrayList<>(); |
|
117 |
} |
|
99 | 118 |
|
100 |
} catch (IOException ioe) {
|
|
101 |
logger.error("Error in Base64 encoding.", ioe);
|
|
102 |
request.getSession().setAttribute("message", "Unable to revoke your token. Please try again later");
|
|
103 |
System.out.println("ERROR >>>> " + ioe.getMessage());
|
|
119 |
if (!refreshToken.getValue().equals(currentRefreshToken)) {
|
|
120 |
oldRefreshTokens.add(refreshToken.getId()+"");
|
|
121 |
}
|
|
122 |
}
|
|
104 | 123 |
|
105 |
} |
|
124 |
System.out.println("Old refresh tokens... " + oldRefreshTokens); |
|
125 |
return oldRefreshTokens; |
|
106 | 126 |
} |
107 | 127 |
} |
modules/dnet-openaire-users/trunk/src/main/webapp/overview.jsp | ||
---|---|---|
88 | 88 |
<h2 class="uk-h2 uk-margin-small-bottom">OpenAIRE APIs Authentication</h2> |
89 | 89 |
<div class="uk-margin-top"> |
90 | 90 |
The OpenAIRE APIs can be accessed over HTTPS both by authenticated and unauthenticated requests. |
91 |
To achieve better rate limits you need to make authenticated requests. We support personal access tokens and service registration. |
|
92 |
For more information please read the <a href="">documentation.</a> |
|
91 |
To achieve <b>better rate limits</b> you need to make <b>authenticated requests</b>. |
|
92 |
<p><span uk-icon="icon:info"></span> For more information please read the <a href="">documentation</a>.</p> |
|
93 |
|
|
93 | 94 |
</div> |
94 | 95 |
<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"> |
95 | 96 |
<div class="uk-padding-small"> |
96 | 97 |
<div class="uk-card uk-card-default uk-card-body"> |
97 | 98 |
<div class=""> <a class="uk-link uk-text-large" href="./personalToken"> Personal token</a></div> |
98 |
<div>mpla mpla mpla</div>
|
|
99 |
<div>Get access to the OpenAIRE APIs with your personal access and refresh token.</div>
|
|
99 | 100 |
|
100 | 101 |
|
101 | 102 |
</div> |
... | ... | |
103 | 104 |
<div class="uk-padding-small"> |
104 | 105 |
<div class="uk-card uk-card-default uk-card-body "> |
105 | 106 |
<div class=""> <a class="uk-link uk-text-large" href="./registeredServices"> Registered Services</a></div> |
106 |
<div>mpla mpla mpla</div>
|
|
107 |
<div>Register your services to get access to the OpenAIRE APIs.</div>
|
|
107 | 108 |
</div> |
108 | 109 |
</div> |
109 | 110 |
</div> |
modules/dnet-openaire-users/trunk/src/main/webapp/personal.jsp | ||
---|---|---|
124 | 124 |
<span id="server_error" class="uk-text-danger uk-text-small uk-float-left">${message}</span> |
125 | 125 |
<c:remove var="message" scope="session" /> |
126 | 126 |
<form id="revoke" name="revoke" action="./personalToken" method="post"> |
127 |
<a class=" uk-text-danger uk-float-right" title="Revoke access token" onClick="document.revoke.submit();"><span uk-icon="refresh" ></span></a>
|
|
127 |
<!-- <a class=" uk-text-danger uk-float-right" title="Revoke access token" onClick="document.revoke.submit();"><span uk-icon="refresh" ></span></a> -->
|
|
128 | 128 |
<a class=" uk-float-right uk-margin-small-left" onclick="copy('accessToken')" title="Copy access token"><span uk-icon="icon:copy"></span></a> |
129 | 129 |
<div class="uk-h5">Your personal access token is</div> |
130 | 130 |
<pre><code id="accessToken">${accessToken}</code></pre> |
131 |
<span uk-icon="icon:info"></span> Your access token is <b>valid for an hour</b>. |
|
131 | 132 |
</form> |
132 | 133 |
</div> |
133 |
<div> |
|
134 |
<a class=" uk-text-danger uk-float-right" title="Revoke refresh token"><span uk-icon="refresh"></span></a> |
|
135 |
<a class=" uk-float-right uk-margin-small-left" onclick="copy('refreshToken')" title="Copy refresh token"><span uk-icon="icon: copy"></span></a> |
|
136 |
<div class="uk-h5">Your refresh token is</div> |
|
137 |
<pre><code id="refreshToken">${refreshToken}</code></pre> |
|
138 |
</div> |
|
139 | 134 |
|
140 | 135 |
<div class="uk-alert-danger uk-alert uk-margin-large-top" > |
141 |
<p><b>Do not share your personal access token. Send your personal access token only over HTTPS.</b></p>
|
|
136 |
<p>Do not share your personal access token. Send your personal access token only over HTTPS.</p>
|
|
142 | 137 |
</div> |
143 |
|
|
144 | 138 |
<div class="uk-alert-primary uk-alert" > |
145 |
For further information on how to use the tokens please visit the <a href="">OpenAIRE API Authentication documentation</a>. |
|
139 |
<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>.
|
|
146 | 140 |
</div> |
141 |
|
|
147 | 142 |
<div> |
148 |
<div class="uk-h5">Revoke tokens</div> |
|
149 |
<div>Mpla mpla mpla</div> |
|
150 |
<a class="uk-button uk-button-danger uk-margin-top"><span uk-icon="refresh"></span>Revoke</a> |
|
143 |
<!--<a class=" uk-text-danger uk-float-right" title="Revoke refresh token"><span uk-icon="refresh"></span></a>--> |
|
144 |
<div class="uk-h5">Do you need a refresh token?</div> |
|
145 |
<p>OpenAIRE refresh token <b>expires after 1 month</b> and allows you to programmatically get a new access token. </p> |
|
146 |
<button type="submit" class="uk-button uk-button-primary" uk-toggle="target: #refreshWarning">Get a refresh token</button> |
|
147 |
<div id="refreshTokenDiv" style="${display_refresh_token}"> |
|
148 |
<c:remove var="display_refresh_token" scope="session"/> |
|
149 |
<div class="uk-alert-warning uk-alert" > |
|
150 |
Please copy your refresh token and store it confidentially. You will not be able to retrieve it. |
|
151 |
</div> |
|
152 |
<div class="uk-alert-danger uk-alert uk-margin-large-top" > |
|
153 |
<p>Do not share your refresh token. Send your personal access token only over HTTPS.</p> |
|
154 |
</div> |
|
155 |
<a class="uk-float-right uk-margin-small-left" onclick="copy('refreshToken')" title="Copy refresh token"><span uk-icon="icon: copy"></span></a> |
|
156 |
<pre><code id="refreshToken">${refreshToken}</code></pre> |
|
157 |
</div> |
|
151 | 158 |
</div> |
159 |
|
|
160 |
<!-- This is the modal --> |
|
161 |
<div id="refreshWarning" uk-modal> |
|
162 |
<div class="uk-modal-dialog uk-modal-body"> |
|
163 |
<form id="refreshForm" action="./personalToken" method="POST"> |
|
164 |
<h2 class="uk-modal-title">Get refresh token</h2> |
|
165 |
<p>In case you already have a refresh token, it will no longer be valid. Do you want to proceed?</p> |
|
166 |
<p class="uk-text-right"> |
|
167 |
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button> |
|
168 |
<button class="uk-button uk-button-primary" type="button" onclick="submit();">Get refresh token</button> |
|
169 |
</p> |
|
170 |
</form> |
|
171 |
</div> |
|
172 |
</div> |
|
152 | 173 |
</div> |
174 |
|
|
153 | 175 |
<!-- END OF CENTER SIDE --> |
154 | 176 |
</div> |
155 | 177 |
</div> |
Also available in: Unified diff
Nre refresh token policy applied. Request for new token, invalidates the old ones.