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<>(); 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<>(); 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<>(); 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 return Framework.doPrivileged(() -> { 146 try (Session session = ds.open(DIRECTORY_NAME)) { 147 DocumentModel entry = session.getEntry(token); 148 if (entry == null) { 149 return null; 150 } 151 return getTokenFromDirectoryEntry(entry); 152 } 153 }); 154 } 155 156 protected NuxeoOAuthToken getTokenFromDirectoryEntry(DocumentModel entry) { 157 return new NuxeoOAuthToken(entry); 158 } 159 160 protected NuxeoOAuthToken storeAccessTokenAsDirectoryEntry(NuxeoOAuthToken aToken) { 161 DirectoryService ds = Framework.getService(DirectoryService.class); 162 return Framework.doPrivileged(() -> { 163 try (Session session = ds.open(DIRECTORY_NAME)) { 164 DocumentModel entry = session.getEntry(aToken.getToken()); 165 if (entry == null) { 166 entry = session.createEntry(Collections.singletonMap("token", aToken.getToken())); 167 } 168 169 aToken.updateEntry(entry); 170 session.updateEntry(entry); 171 172 return getTokenFromDirectoryEntry(session.getEntry(aToken.getToken())); 173 } 174 }); 175 } 176 177 @Override 178 public OAuthToken createRequestToken(String consumerKey, String callBack) { 179 180 NuxeoOAuthToken rToken = new NuxeoOAuthToken(consumerKey, callBack); 181 String token = "NX-RT-" + consumerKey + "-" + UUID.randomUUID().toString(); 182 rToken.token = token; 183 rToken.tokenSecret = "NX-RTS-" + consumerKey + UUID.randomUUID().toString(); 184 rToken.type = OAuthToken.Type.REQUEST; 185 requestTokenStore.put(token, rToken); 186 187 return rToken; 188 } 189 190 @Override 191 public OAuthToken getAccessToken(String token) { 192 193 try { 194 return getTokenFromDirectory(token); 195 } catch (DirectoryException e) { 196 log.error("Error while accessing Token SQL storage", e); 197 return null; 198 } 199 } 200 201 @Override 202 public OAuthToken getRequestToken(String token) { 203 return requestTokenStore.get(token); 204 } 205 206 @Override 207 public List<OAuthToken> listAccessTokenForConsumer(String consumerKey) { 208 List<OAuthToken> result = new ArrayList<>(); 209 210 DirectoryService ds = Framework.getService(DirectoryService.class); 211 try (Session session = ds.open(DIRECTORY_NAME)) { 212 Map<String, Serializable> filter = new HashMap<>(); 213 filter.put("consumerKey", consumerKey); 214 filter.put("clientToken", 0); 215 DocumentModelList entries = session.query(filter); 216 for (DocumentModel entry : entries) { 217 result.add(new NuxeoOAuthToken(entry)); 218 } 219 } catch (DirectoryException e) { 220 log.error("Error during token listing", e); 221 } 222 return result; 223 } 224 225 @Override 226 public List<OAuthToken> listAccessTokenForUser(String login) { 227 List<OAuthToken> result = new ArrayList<>(); 228 DirectoryService ds = Framework.getService(DirectoryService.class); 229 try (Session session = ds.open(DIRECTORY_NAME)) { 230 Map<String, Serializable> filter = new HashMap<>(); 231 filter.put("nuxeoLogin", login); 232 filter.put("clientToken", 0); 233 DocumentModelList entries = session.query(filter); 234 for (DocumentModel entry : entries) { 235 result.add(new NuxeoOAuthToken(entry)); 236 } 237 } catch (DirectoryException e) { 238 log.error("Error during token listing", e); 239 } 240 return result; 241 } 242 243 @Override 244 public void removeAccessToken(String token) { 245 DirectoryService ds = Framework.getService(DirectoryService.class); 246 try (Session session = ds.open(DIRECTORY_NAME)) { 247 session.deleteEntry(token); 248 } 249 } 250 251 @Override 252 public void removeRequestToken(String token) { 253 requestTokenStore.remove(token); 254 } 255 256}