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