001/*
002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nelson Silva
018 */
019package org.nuxeo.ecm.platform.oauth2.tokens;
020
021import java.time.Instant;
022import java.util.Calendar;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.concurrent.TimeUnit;
026
027import org.apache.commons.text.CharacterPredicates;
028import org.apache.commons.text.RandomStringGenerator;
029import org.apache.commons.text.RandomStringGenerator.Builder;
030import org.nuxeo.ecm.core.api.DocumentModel;
031
032import com.google.api.client.auth.oauth2.StoredCredential;
033
034public class NuxeoOAuth2Token {
035
036    private static final RandomStringGenerator GENERATOR = new Builder().filteredBy(CharacterPredicates.LETTERS,
037            CharacterPredicates.DIGITS).withinRange('0', 'z').build();
038
039    public static final String SCHEMA = "oauth2Token";
040
041    public static final String KEY_SERVICE_LOGIN = "serviceLogin";
042
043    public static final String KEY_NUXEO_LOGIN = "nuxeoLogin";
044
045    /**
046     * @since 11.1
047     */
048    public static final String KEY_SERVICE_NAME = "serviceName";
049
050    protected Long id;
051
052    protected String serviceName;
053
054    protected String nuxeoLogin;
055
056    protected String accessToken;
057
058    protected String clientId;
059
060    protected Calendar creationDate;
061
062    private String refreshToken;
063
064    private Long expirationTimeMilliseconds;
065
066    private boolean isShared;
067
068    protected String sharedWith;
069
070    protected String serviceLogin;
071
072    public NuxeoOAuth2Token(long expirationTimeMilliseconds, String clientId) {
073        this("", "", expirationTimeMilliseconds);
074        this.clientId = clientId;
075        refresh();
076    }
077
078    public NuxeoOAuth2Token(String accessToken, String refreshToken, Long expirationTimeMilliseconds) {
079        this.accessToken = accessToken;
080        this.refreshToken = refreshToken;
081        this.expirationTimeMilliseconds = expirationTimeMilliseconds;
082        this.creationDate = Calendar.getInstance();
083        this.isShared = false;
084        this.sharedWith = "";
085    }
086
087    public NuxeoOAuth2Token(StoredCredential credential) {
088        this(credential.getAccessToken(), credential.getRefreshToken(), credential.getExpirationTimeMilliseconds());
089    }
090
091    public NuxeoOAuth2Token(DocumentModel entry) {
092        this.id = (Long) entry.getProperty(SCHEMA, "id");
093        this.accessToken = (String) entry.getProperty(SCHEMA, "accessToken");
094        this.refreshToken = (String) entry.getProperty(SCHEMA, "refreshToken");
095        this.expirationTimeMilliseconds = (Long) entry.getProperty(SCHEMA, "expirationTimeMilliseconds");
096        this.serviceName = (String) entry.getProperty(SCHEMA, "serviceName");
097        this.nuxeoLogin = (String) entry.getProperty(SCHEMA, "nuxeoLogin");
098        this.clientId = (String) entry.getProperty(SCHEMA, "clientId");
099        this.creationDate = (Calendar) entry.getProperty(SCHEMA, "creationDate");
100        this.isShared = (Boolean) entry.getProperty(SCHEMA, "isShared");
101        this.sharedWith = (String) entry.getProperty(SCHEMA, "sharedWith");
102        this.serviceLogin = (String) entry.getProperty(SCHEMA, "serviceLogin");
103    }
104
105    public static StoredCredential asCredential(DocumentModel entry) {
106        StoredCredential credential = new StoredCredential();
107        String accessToken = (String) entry.getProperty(SCHEMA, "accessToken");
108        String refreshToken = (String) entry.getProperty(SCHEMA, "refreshToken");
109        Long expirationTimeMilliseconds = (Long) entry.getProperty(SCHEMA, "expirationTimeMilliseconds");
110        credential.setAccessToken(accessToken);
111        credential.setRefreshToken(refreshToken);
112        credential.setExpirationTimeMilliseconds(expirationTimeMilliseconds);
113        return credential;
114    }
115
116    public Map<String, Object> toMap() {
117        Map<String, Object> map = new HashMap<>();
118        map.put("serviceName", serviceName);
119        map.put("nuxeoLogin", nuxeoLogin);
120        map.put("accessToken", accessToken);
121        map.put("refreshToken", refreshToken);
122        map.put("expirationTimeMilliseconds", expirationTimeMilliseconds);
123        map.put("clientId", clientId);
124        map.put("creationDate", creationDate);
125        map.put("isShared", isShared);
126        map.put("sharedWith", sharedWith);
127        map.put("serviceLogin", serviceLogin);
128        return map;
129    }
130
131    public Map<String, Object> toJsonObject() {
132        Map<String, Object> m = new HashMap<>();
133        m.put("access_token", accessToken);
134        m.put("refresh_token", refreshToken);
135        m.put("token_type", "bearer");
136        // Lifetime in seconds of the access token, see https://tools.ietf.org/html/rfc6749#section-5.1.
137        // Must be a whole number otherwise some clients might fail reading the token response.
138        m.put("expires_in", TimeUnit.MILLISECONDS.toSeconds(
139                creationDate.getTimeInMillis() + expirationTimeMilliseconds - Instant.now().toEpochMilli()));
140
141        return m;
142    }
143
144    public void updateEntry(DocumentModel entry) {
145        entry.setProperty(SCHEMA, "serviceName", this.serviceName);
146        entry.setProperty(SCHEMA, "nuxeoLogin", this.nuxeoLogin);
147        entry.setProperty(SCHEMA, "accessToken", this.accessToken);
148        entry.setProperty(SCHEMA, "refreshToken", this.refreshToken);
149        entry.setProperty(SCHEMA, "expirationTimeMilliseconds", this.expirationTimeMilliseconds);
150        entry.setProperty(SCHEMA, "clientId", this.clientId);
151        entry.setProperty(SCHEMA, "isShared", this.isShared);
152        entry.setProperty(SCHEMA, "sharedWith", this.sharedWith);
153        entry.setProperty(SCHEMA, "serviceLogin", this.serviceLogin);
154    }
155
156    public void refresh() {
157        accessToken = GENERATOR.generate(32);
158        refreshToken = GENERATOR.generate(64);
159        creationDate = Calendar.getInstance();
160    }
161
162    public boolean isExpired() {
163        return creationDate != null && creationDate.getTimeInMillis()
164                + expirationTimeMilliseconds < Calendar.getInstance().getTimeInMillis();
165    }
166
167    public void setServiceName(String serviceName) {
168        this.serviceName = serviceName;
169    }
170
171    public void setNuxeoLogin(String userId) {
172        this.nuxeoLogin = userId;
173    }
174
175    public String getNuxeoLogin() {
176        return nuxeoLogin;
177    }
178
179    public String getAccessToken() {
180        return accessToken;
181    }
182
183    public void setAccessToken(String accessToken) {
184        this.accessToken = accessToken;
185    }
186
187    public String getRefreshToken() {
188        return refreshToken;
189    }
190
191    public void setRefreshToken(String refreshToken) {
192        this.refreshToken = refreshToken;
193    }
194
195    public Long getExpirationTimeMilliseconds() {
196        return expirationTimeMilliseconds;
197    }
198
199    public void setExpirationTimeMilliseconds(Long expirationTimeMilliseconds) {
200        this.expirationTimeMilliseconds = expirationTimeMilliseconds;
201    }
202
203    public String getServiceName() {
204        return serviceName;
205    }
206
207    public String getClientId() {
208        return clientId;
209    }
210
211    public void setClientId(String clientId) {
212        this.clientId = clientId;
213    }
214
215    public boolean isShared() {
216        return isShared;
217    }
218
219    public void setIsShared(boolean isShared) {
220        this.isShared = isShared;
221    }
222
223    public String getSharedWith() {
224        return sharedWith;
225    }
226
227    public void setSharedWith(String sharedWith) {
228        this.sharedWith = sharedWith;
229    }
230
231    public String getServiceLogin() {
232        return serviceLogin;
233    }
234
235    public void setServiceLogin(String serviceLogin) {
236        this.serviceLogin = serviceLogin;
237    }
238
239    public Calendar getCreationDate() {
240        return creationDate;
241    }
242
243    public void setCreationDate(Calendar creationDate) {
244        this.creationDate = creationDate;
245    }
246
247    public Long getId() {
248        return id;
249    }
250
251}