/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.example.ext.oauth.mongo; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import org.restlet.ext.oauth.OAuthError; import org.restlet.ext.oauth.OAuthException; import org.restlet.ext.oauth.OAuthResourceDefs; import org.restlet.ext.oauth.internal.AbstractTokenManager; import org.restlet.ext.oauth.internal.AuthSession; import org.restlet.ext.oauth.internal.Client; import org.restlet.ext.oauth.internal.Token; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; /** * MongoDB implementation of TokenManager interface. * * @author Shotaro Uchida <fantom@xmaker.mx> */ public class MongoTokenManager extends AbstractTokenManager implements OAuthResourceDefs { private DBCollection tokens; private DBCollection sessions; public MongoTokenManager(DB db) { tokens = db.getCollection("tokens"); sessions = db.getCollection("sessions"); } public Token generateToken(Client client, String username, String[] scope) throws OAuthException { DBObject token = tokens.findOne(createQuery(client, username)); if (token == null) { token = new BasicDBObject(); token.put(CLIENT_ID, client.getClientId()); if (username != null) { token.put(USERNAME, username); } } token.put(SCOPE, Arrays.asList(scope)); token.put(EXPIRES_IN, getExpirePeriod()); token.put(TOKEN_TYPE, TOKEN_TYPE_BEARER); token.put(ACCESS_TOKEN, generateRawToken()); token.put(REFRESH_TOKEN, generateRawToken()); token.put(MongoToken.TIMESTAMP, (int) (System.currentTimeMillis() / 1000)); // Perform Upsert tokens.ensureIndex(new BasicDBObject(ACCESS_TOKEN, "1"), new BasicDBObject("unique", true)); tokens.ensureIndex(new BasicDBObject(REFRESH_TOKEN, "1"), new BasicDBObject("unique", true)); tokens.save(token); return new MongoToken(token); } @SuppressWarnings("unchecked") public Token refreshToken(Client client, String refreshToken, String[] scope) throws OAuthException { DBObject token = tokens.findOne(new BasicDBObject(REFRESH_TOKEN, refreshToken)); if (token == null) { throw new OAuthException(OAuthError.invalid_grant, "Invalid refresh token.", null); } // ensure that the refresh token was issued to the authenticated client if (!token.get(CLIENT_ID).equals(client.getClientId())) { throw new OAuthException(OAuthError.invalid_grant, "The refresh token was not issued to the client.", null); } /* * The requested scope MUST NOT include any scope not originally granted * by the resource owner, and if omitted is treated as equal to the * scope originally granted by the resource owner. (6. Refreshing an * Access Token) */ if (scope != null && scope.length != 0) { List<String> newScopeList = Arrays.asList(scope); if (!((List<String>) token.get(SCOPE)).containsAll(newScopeList)) { throw new OAuthException( OAuthError.invalid_scope, "The requested scope is exceeds the scope granted by the resource owner.", null); } token.put(SCOPE, newScopeList); } token.put(ACCESS_TOKEN, generateRawToken()); if (isUpdateRefreshToken()) { token.put(REFRESH_TOKEN, generateRawToken()); } // Perform Upsert tokens.ensureIndex(new BasicDBObject(ACCESS_TOKEN, "1"), new BasicDBObject("unique", true)); tokens.ensureIndex(new BasicDBObject(REFRESH_TOKEN, "1"), new BasicDBObject("unique", true)); tokens.save(token); return new MongoToken(token); } private DBObject createQuery(Client client, String username) { BasicDBObject query = new BasicDBObject(CLIENT_ID, client.getClientId()); if (username != null) { query.append(USERNAME, username); } else { query.append(USERNAME, new BasicDBObject("$exists", false)); } return query; } public String storeSession(AuthSession session) throws OAuthException { BasicDBObject sessionObj = new BasicDBObject(); Map<String, Object> map = session.toMap(); for (String key : map.keySet()) { sessionObj.put(key, map.get(key)); } String code = generateRawCode(); sessionObj.put("_id", code); sessions.insert(sessionObj); return code; } @SuppressWarnings("unchecked") public AuthSession restoreSession(String code) throws OAuthException { DBObject sessionObj = sessions.findOne(new BasicDBObject("_id", code)); if (sessionObj == null) { throw new OAuthException(OAuthError.invalid_grant, "Invalid code.", null); } return AuthSession.toAuthSession((Map<String, Object>) sessionObj .toMap()); } public Token validateToken(String accessToken) throws OAuthException { DBObject token = tokens.findOne(new BasicDBObject(ACCESS_TOKEN, accessToken)); if (token == null) { throw new OAuthException(OAuthError.invalid_token, "The access token revoked.", null); } MongoToken tokenImpl = new MongoToken(token); if (tokenImpl.isExpired()) { throw new OAuthException(OAuthError.invalid_token, "The access token expired.", null); } return tokenImpl; } public Token findToken(Client client, String username) { DBObject token = tokens.findOne(createQuery(client, username)); if (token == null) { return null; } return new MongoToken(token); } public Token[] findTokens(String username) { DBCursor cursor = tokens.find(new BasicDBObject(USERNAME, username)); ArrayList<Token> list = new ArrayList<Token>(); while (cursor.hasNext()) { DBObject token = cursor.next(); list.add(new MongoToken(token)); } return list.toArray(new Token[list.size()]); } public Token[] findTokens(Client client) { DBCursor cursor = tokens.find(new BasicDBObject(CLIENT_ID, client .getClientId())); ArrayList<Token> list = new ArrayList<Token>(); while (cursor.hasNext()) { DBObject token = cursor.next(); list.add(new MongoToken(token)); } return list.toArray(new Token[list.size()]); } public void revokeToken(Client client, String username) { tokens.remove(createQuery(client, username)); } public void revokeAllTokens(String username) { tokens.remove(new BasicDBObject(USERNAME, username)); } public void revokeAllTokens(Client client) { tokens.remove(new BasicDBObject(CLIENT_ID, client.getClientId())); } }