Merge "Cache for OAuth access tokens"
This commit is contained in:
commit
a6d646b658
@ -14,17 +14,33 @@
|
||||
|
||||
package com.google.gerrit.extensions.auth.oauth;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/* OAuth token */
|
||||
public class OAuthToken {
|
||||
public class OAuthToken implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String token;
|
||||
private final String secret;
|
||||
private final String raw;
|
||||
|
||||
/**
|
||||
* Time of expiration of this token, or {@code Long#MAX_VALUE} if this
|
||||
* token never expires, or time of expiration is unknown.
|
||||
*/
|
||||
private final long expiresAt;
|
||||
|
||||
public OAuthToken(String token, String secret, String raw) {
|
||||
this(token, secret, raw, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public OAuthToken(String token, String secret, String raw,
|
||||
long expiresAt) {
|
||||
this.token = token;
|
||||
this.secret = secret;
|
||||
this.raw = raw;
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
@ -38,4 +54,12 @@ public class OAuthToken {
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public long getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return System.currentTimeMillis() > expiresAt;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.extensions.auth.oauth;
|
||||
|
||||
import com.google.gerrit.extensions.annotations.ExtensionPoint;
|
||||
|
||||
@ExtensionPoint
|
||||
public interface OAuthTokenEncrypter {
|
||||
|
||||
/**
|
||||
* Encrypts the secret parts of the given OAuth access token.
|
||||
*
|
||||
* @param unencrypted a raw OAuth access token.
|
||||
*/
|
||||
OAuthToken encrypt(OAuthToken unencrypted);
|
||||
|
||||
/**
|
||||
* Decrypts the secret parts of the given OAuth access token.
|
||||
*
|
||||
* @param encrypted an encryppted OAuth access token.
|
||||
*/
|
||||
OAuthToken decrypt(OAuthToken encrypted);
|
||||
}
|
@ -31,6 +31,7 @@ import com.google.gerrit.server.account.AccountException;
|
||||
import com.google.gerrit.server.account.AccountManager;
|
||||
import com.google.gerrit.server.account.AuthRequest;
|
||||
import com.google.gerrit.server.account.AuthResult;
|
||||
import com.google.gerrit.server.auth.oauth.OAuthTokenCache;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
@ -58,8 +59,8 @@ class OAuthSession {
|
||||
private final Provider<IdentifiedUser> identifiedUser;
|
||||
private final AccountManager accountManager;
|
||||
private final CanonicalWebUrl urlProvider;
|
||||
private final OAuthTokenCache tokenCache;
|
||||
private OAuthServiceProvider serviceProvider;
|
||||
private OAuthToken token;
|
||||
private OAuthUserInfo user;
|
||||
private String redirectToken;
|
||||
private boolean linkMode;
|
||||
@ -68,16 +69,18 @@ class OAuthSession {
|
||||
OAuthSession(DynamicItem<WebSession> webSession,
|
||||
Provider<IdentifiedUser> identifiedUser,
|
||||
AccountManager accountManager,
|
||||
CanonicalWebUrl urlProvider) {
|
||||
CanonicalWebUrl urlProvider,
|
||||
OAuthTokenCache tokenCache) {
|
||||
this.state = generateRandomState();
|
||||
this.identifiedUser = identifiedUser;
|
||||
this.webSession = webSession;
|
||||
this.accountManager = accountManager;
|
||||
this.urlProvider = urlProvider;
|
||||
this.tokenCache = tokenCache;
|
||||
}
|
||||
|
||||
boolean isLoggedIn() {
|
||||
return token != null && user != null;
|
||||
return tokenCache.has(user);
|
||||
}
|
||||
|
||||
boolean isOAuthFinal(HttpServletRequest request) {
|
||||
@ -95,9 +98,12 @@ class OAuthSession {
|
||||
}
|
||||
|
||||
log.debug("Login-Retrieve-User " + this);
|
||||
token = oauth.getAccessToken(new OAuthVerifier(request.getParameter("code")));
|
||||
|
||||
OAuthToken token = oauth.getAccessToken(
|
||||
new OAuthVerifier(request.getParameter("code")));
|
||||
user = oauth.getUserInfo(token);
|
||||
if (user != null && token != null) {
|
||||
tokenCache.put(user, token);
|
||||
}
|
||||
|
||||
if (isLoggedIn()) {
|
||||
log.debug("Login-SUCCESS " + this);
|
||||
@ -211,7 +217,7 @@ class OAuthSession {
|
||||
}
|
||||
|
||||
void logout() {
|
||||
token = null;
|
||||
tokenCache.remove(user);
|
||||
user = null;
|
||||
redirectToken = null;
|
||||
serviceProvider = null;
|
||||
@ -243,7 +249,8 @@ class OAuthSession {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OAuthSession [token=" + token + ", user=" + user + "]";
|
||||
return "OAuthSession [token=" + tokenCache.get(user) + ", user=" + user
|
||||
+ "]";
|
||||
}
|
||||
|
||||
public void setServiceProvider(OAuthServiceProvider provider) {
|
||||
|
@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.gerrit.server.auth.oauth;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthToken;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthTokenEncrypter;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthUserInfo;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.server.cache.CacheModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
|
||||
@Singleton
|
||||
public class OAuthTokenCache {
|
||||
public static final String OAUTH_TOKENS = "oauth_tokens";
|
||||
|
||||
private final DynamicItem<OAuthTokenEncrypter> encrypter;
|
||||
|
||||
public static Module module() {
|
||||
return new CacheModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
persist(OAUTH_TOKENS, String.class, OAuthToken.class);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final Cache<String, OAuthToken> cache;
|
||||
|
||||
@Inject
|
||||
OAuthTokenCache(@Named(OAUTH_TOKENS) Cache<String, OAuthToken> cache,
|
||||
DynamicItem<OAuthTokenEncrypter> encrypter) {
|
||||
this.cache = cache;
|
||||
this.encrypter = encrypter;
|
||||
}
|
||||
|
||||
public boolean has(OAuthUserInfo user) {
|
||||
return user != null
|
||||
? cache.getIfPresent(user.getUserName()) != null
|
||||
: false;
|
||||
}
|
||||
|
||||
public OAuthToken get(OAuthUserInfo user) {
|
||||
return user != null
|
||||
? get(user.getUserName())
|
||||
: null;
|
||||
}
|
||||
|
||||
public OAuthToken get(String userName) {
|
||||
OAuthToken accessToken = cache.getIfPresent(userName);
|
||||
if (accessToken == null) {
|
||||
return null;
|
||||
}
|
||||
accessToken = decrypt(accessToken);
|
||||
if (accessToken.isExpired()) {
|
||||
cache.invalidate(userName);
|
||||
return null;
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void put(OAuthUserInfo user, OAuthToken accessToken) {
|
||||
cache.put(checkNotNull(user.getUserName()),
|
||||
encrypt(checkNotNull(accessToken)));
|
||||
}
|
||||
|
||||
public void remove(OAuthUserInfo user) {
|
||||
if (user != null) {
|
||||
cache.invalidate(user.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
private OAuthToken encrypt(OAuthToken token) {
|
||||
OAuthTokenEncrypter enc = encrypter.get();
|
||||
if (enc == null) {
|
||||
return token;
|
||||
}
|
||||
return enc.encrypt(token);
|
||||
}
|
||||
|
||||
private OAuthToken decrypt(OAuthToken token) {
|
||||
OAuthTokenEncrypter enc = encrypter.get();
|
||||
if (enc == null) {
|
||||
return token;
|
||||
}
|
||||
return enc.decrypt(token);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import com.google.gerrit.audit.AuditModule;
|
||||
import com.google.gerrit.common.EventListener;
|
||||
import com.google.gerrit.common.UserScopedEventListener;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthLoginProvider;
|
||||
import com.google.gerrit.extensions.auth.oauth.OAuthTokenEncrypter;
|
||||
import com.google.gerrit.extensions.config.CapabilityDefinition;
|
||||
import com.google.gerrit.extensions.config.CloneCommand;
|
||||
import com.google.gerrit.extensions.config.DownloadCommand;
|
||||
@ -74,6 +75,7 @@ import com.google.gerrit.server.account.VersionedAuthorizedKeys;
|
||||
import com.google.gerrit.server.api.accounts.AccountExternalIdCreator;
|
||||
import com.google.gerrit.server.auth.AuthBackend;
|
||||
import com.google.gerrit.server.auth.UniversalAuthBackend;
|
||||
import com.google.gerrit.server.auth.oauth.OAuthTokenCache;
|
||||
import com.google.gerrit.server.avatar.AvatarProvider;
|
||||
import com.google.gerrit.server.cache.CacheRemovalListener;
|
||||
import com.google.gerrit.server.change.ChangeJson;
|
||||
@ -191,6 +193,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
install(SectionSortCache.module());
|
||||
install(SubmitStrategy.module());
|
||||
install(TagCache.module());
|
||||
install(OAuthTokenCache.module());
|
||||
|
||||
install(new AccessControlModule());
|
||||
install(new CmdLineParserModule());
|
||||
@ -315,6 +318,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
DynamicSet.setOf(binder(), ProjectWebLink.class);
|
||||
DynamicSet.setOf(binder(), BranchWebLink.class);
|
||||
DynamicMap.mapOf(binder(), OAuthLoginProvider.class);
|
||||
DynamicItem.itemOf(binder(), OAuthTokenEncrypter.class);
|
||||
DynamicSet.setOf(binder(), AccountExternalIdCreator.class);
|
||||
DynamicSet.setOf(binder(), WebUiPlugin.class);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user