Project

General

Profile

« Previous | Next » 

Revision 59621

Nre refresh token policy applied. Request for new token, invalidates the old ones.

View differences:

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