001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.oauth.tokens; 021 022import java.io.Serializable; 023import java.util.ArrayList; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.UUID; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.core.api.DocumentModelList; 033import org.nuxeo.ecm.directory.DirectoryException; 034import org.nuxeo.ecm.directory.Session; 035import org.nuxeo.ecm.directory.api.DirectoryService; 036import org.nuxeo.runtime.api.Framework; 037import org.nuxeo.runtime.model.DefaultComponent; 038 039/** 040 * Service implementation for {@link OAuthTokenStore}. 041 * <p> 042 * This service is responsible for managing storage of the {@link OAuthToken}. A simple SQL Directory is used for ACCESS 043 * Token whereas a simple in memory storage is used for REQUEST Tokens. 044 * 045 * @author tiry 046 */ 047public class OAuthTokenStoreImpl extends DefaultComponent implements OAuthTokenStore { 048 049 protected static final Log log = LogFactory.getLog(OAuthTokenStoreImpl.class); 050 051 public static final String DIRECTORY_NAME = "oauthTokens"; 052 053 protected Map<String, OAuthToken> requestTokenStore = new HashMap<String, OAuthToken>(); 054 055 @Override 056 public OAuthToken addVerifierToRequestToken(String token, Long duration) { 057 NuxeoOAuthToken rToken = (NuxeoOAuthToken) getRequestToken(token); 058 if (rToken != null) { 059 rToken.verifier = "NX-VERIF-" + UUID.randomUUID().toString(); 060 rToken.durationInMinutes = duration; 061 } 062 return rToken; 063 } 064 065 @Override 066 public OAuthToken createAccessTokenFromRequestToken(OAuthToken requestToken) { 067 NuxeoOAuthToken aToken = new NuxeoOAuthToken((NuxeoOAuthToken) requestToken); 068 String token = "NX-AT-" + UUID.randomUUID().toString(); 069 aToken.token = token; 070 aToken.tokenSecret = "NX-ATS-" + UUID.randomUUID().toString(); 071 aToken.type = OAuthToken.Type.ACCESS; 072 073 try { 074 aToken = storeAccessTokenAsDirectoryEntry(aToken); 075 removeRequestToken(requestToken.getToken()); 076 return aToken; 077 } catch (DirectoryException e) { 078 log.error("Error during directory persistence", e); 079 return null; 080 } 081 } 082 083 @Override 084 public NuxeoOAuthToken getClientAccessToken(String appId, String owner) { 085 DirectoryService ds = Framework.getService(DirectoryService.class); 086 try (Session session = ds.open(DIRECTORY_NAME)) { 087 Map<String, Serializable> filter = new HashMap<String, Serializable>(); 088 filter.put("appId", appId); 089 filter.put("clientId", owner); 090 filter.put("clientToken", 1); 091 DocumentModelList entries = session.query(filter); 092 if (entries.size() == 0) { 093 return null; 094 } 095 if (entries.size() > 1) { 096 log.error("Found several tokens"); 097 } 098 return getTokenFromDirectoryEntry(entries.get(0)); 099 } 100 } 101 102 @Override 103 public void removeClientAccessToken(String appId, String owner) { 104 DirectoryService ds = Framework.getService(DirectoryService.class); 105 try (Session session = ds.open(DIRECTORY_NAME)) { 106 Map<String, Serializable> filter = new HashMap<String, Serializable>(); 107 filter.put("appId", appId); 108 filter.put("clientId", owner); 109 filter.put("clientToken", 1); 110 DocumentModelList entries = session.query(filter); 111 if (entries.size() == 0) { 112 return; 113 } 114 if (entries.size() > 1) { 115 log.error("Found several tokens"); 116 } 117 session.deleteEntry(entries.get(0)); 118 } 119 } 120 121 @Override 122 public void storeClientAccessToken(String consumerKey, String callBack, String token, String tokenSecret, 123 String appId, String owner) { 124 NuxeoOAuthToken aToken = new NuxeoOAuthToken(consumerKey, callBack); 125 aToken.token = token; 126 aToken.tokenSecret = tokenSecret; 127 if (appId != null) { 128 aToken.appId = appId; 129 } 130 131 aToken.clientToken = true; 132 aToken.clientId = owner; 133 try { 134 aToken = storeAccessTokenAsDirectoryEntry(aToken); 135 } catch (DirectoryException e) { 136 log.error("Error during directory persistence", e); 137 } 138 } 139 140 protected NuxeoOAuthToken getTokenFromDirectory(String token) { 141 DirectoryService ds = Framework.getService(DirectoryService.class); 142 try (Session session = ds.open(DIRECTORY_NAME)) { 143 DocumentModel entry = session.getEntry(token); 144 if (entry == null) { 145 return null; 146 } 147 return getTokenFromDirectoryEntry(entry); 148 } 149 } 150 151 protected NuxeoOAuthToken getTokenFromDirectoryEntry(DocumentModel entry) { 152 return new NuxeoOAuthToken(entry); 153 } 154 155 protected NuxeoOAuthToken storeAccessTokenAsDirectoryEntry(NuxeoOAuthToken aToken) { 156 DirectoryService ds = Framework.getService(DirectoryService.class); 157 try (Session session = ds.open(DIRECTORY_NAME)) { 158 DocumentModel entry = session.getEntry(aToken.getToken()); 159 if (entry == null) { 160 Map<String, Object> init = new HashMap<String, Object>(); 161 init.put("token", aToken.getToken()); 162 entry = session.createEntry(init); 163 } 164 165 aToken.updateEntry(entry); 166 session.updateEntry(entry); 167 168 return getTokenFromDirectoryEntry(session.getEntry(aToken.getToken())); 169 } 170 } 171 172 @Override 173 public OAuthToken createRequestToken(String consumerKey, String callBack) { 174 175 NuxeoOAuthToken rToken = new NuxeoOAuthToken(consumerKey, callBack); 176 String token = "NX-RT-" + consumerKey + "-" + UUID.randomUUID().toString(); 177 rToken.token = token; 178 rToken.tokenSecret = "NX-RTS-" + consumerKey + UUID.randomUUID().toString(); 179 rToken.type = OAuthToken.Type.REQUEST; 180 requestTokenStore.put(token, rToken); 181 182 return rToken; 183 } 184 185 @Override 186 public OAuthToken getAccessToken(String token) { 187 188 try { 189 return getTokenFromDirectory(token); 190 } catch (DirectoryException e) { 191 log.error("Error while accessing Token SQL storage", e); 192 return null; 193 } 194 } 195 196 @Override 197 public OAuthToken getRequestToken(String token) { 198 return requestTokenStore.get(token); 199 } 200 201 @Override 202 public List<OAuthToken> listAccessTokenForConsumer(String consumerKey) { 203 List<OAuthToken> result = new ArrayList<OAuthToken>(); 204 205 DirectoryService ds = Framework.getService(DirectoryService.class); 206 try (Session session = ds.open(DIRECTORY_NAME)) { 207 Map<String, Serializable> filter = new HashMap<String, Serializable>(); 208 filter.put("consumerKey", consumerKey); 209 filter.put("clientToken", 0); 210 DocumentModelList entries = session.query(filter); 211 for (DocumentModel entry : entries) { 212 result.add(new NuxeoOAuthToken(entry)); 213 } 214 } catch (DirectoryException e) { 215 log.error("Error during token listing", e); 216 } 217 return result; 218 } 219 220 @Override 221 public List<OAuthToken> listAccessTokenForUser(String login) { 222 List<OAuthToken> result = new ArrayList<OAuthToken>(); 223 DirectoryService ds = Framework.getService(DirectoryService.class); 224 try (Session session = ds.open(DIRECTORY_NAME)) { 225 Map<String, Serializable> filter = new HashMap<>(); 226 filter.put("nuxeoLogin", login); 227 filter.put("clientToken", 0); 228 DocumentModelList entries = session.query(filter); 229 for (DocumentModel entry : entries) { 230 result.add(new NuxeoOAuthToken(entry)); 231 } 232 } catch (DirectoryException e) { 233 log.error("Error during token listing", e); 234 } 235 return result; 236 } 237 238 @Override 239 public void removeAccessToken(String token) { 240 DirectoryService ds = Framework.getService(DirectoryService.class); 241 try (Session session = ds.open(DIRECTORY_NAME)) { 242 session.deleteEntry(token); 243 } 244 } 245 246 @Override 247 public void removeRequestToken(String token) { 248 requestTokenStore.remove(token); 249 } 250 251}