Implementation of OAuth2

This commit is contained in:
Winston Li 2015-10-25 13:44:38 +00:00
parent c3db415ce7
commit 1872eba223
18 changed files with 281 additions and 100 deletions

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.bridge; package uk.ac.ic.wlgitbridge.bridge;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException; import org.eclipse.jgit.transport.ServiceMayNotContinueException;
@ -8,6 +9,7 @@ import uk.ac.ic.wlgitbridge.data.ProjectLock;
import uk.ac.ic.wlgitbridge.data.ShutdownHook; import uk.ac.ic.wlgitbridge.data.ShutdownHook;
import uk.ac.ic.wlgitbridge.data.model.DataStore; import uk.ac.ic.wlgitbridge.data.model.DataStore;
import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory; import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest; import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException; import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException;
@ -43,9 +45,9 @@ public class BridgeAPI {
mainProjectLock.unlockForProject(projectName); mainProjectLock.unlockForProject(projectName);
} }
public boolean repositoryExists(String projectName) throws ServiceMayNotContinueException { public boolean repositoryExists(Credential oauth2, String projectName) throws ServiceMayNotContinueException, ForbiddenException {
lockForProject(projectName); lockForProject(projectName);
GetDocRequest getDocRequest = new GetDocRequest(projectName); GetDocRequest getDocRequest = new GetDocRequest(oauth2, projectName);
getDocRequest.request(); getDocRequest.request();
try { try {
getDocRequest.getResult().getVersionID(); getDocRequest.getResult().getVersionID();
@ -61,19 +63,19 @@ public class BridgeAPI {
return true; return true;
} }
public void getWritableRepositories(String projectName, Repository repository) throws IOException, SnapshotPostException, GitAPIException { public void getWritableRepositories(Credential oauth2, String projectName, Repository repository) throws IOException, SnapshotPostException, GitAPIException, ForbiddenException {
Util.sout("Fetching project: " + projectName); Util.sout("Fetching project: " + projectName);
dataStore.updateProjectWithName(projectName, repository); dataStore.updateProjectWithName(oauth2, projectName, repository);
} }
public void putDirectoryContentsToProjectWithName(String projectName, RawDirectory directoryContents, RawDirectory oldDirectoryContents, String hostname) throws SnapshotPostException, IOException { public void putDirectoryContentsToProjectWithName(Credential oauth2, String projectName, RawDirectory directoryContents, RawDirectory oldDirectoryContents, String hostname) throws SnapshotPostException, IOException, ForbiddenException {
mainProjectLock.lockForProject(projectName); mainProjectLock.lockForProject(projectName);
CandidateSnapshot candidate = null; CandidateSnapshot candidate = null;
try { try {
Util.sout("Pushing project: " + projectName); Util.sout("Pushing project: " + projectName);
String postbackKey = postbackManager.makeKeyForProject(projectName); String postbackKey = postbackManager.makeKeyForProject(projectName);
candidate = dataStore.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, oldDirectoryContents); candidate = dataStore.createCandidateSnapshotFromProjectWithContents(projectName, directoryContents, oldDirectoryContents);
PushRequest pushRequest = new PushRequest(candidate, postbackKey); PushRequest pushRequest = new PushRequest(oauth2, candidate, postbackKey);
pushRequest.request(); pushRequest.request();
PushResult result = pushRequest.getResult(); PushResult result = pushRequest.getResult();
if (result.wasSuccessful()) { if (result.wasSuccessful()) {

View file

@ -1,9 +1,11 @@
package uk.ac.ic.wlgitbridge.bridge; package uk.ac.ic.wlgitbridge.bridge;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException; import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException; import uk.ac.ic.wlgitbridge.snapshot.getdoc.exception.InvalidProjectException;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.SnapshotPostException; import uk.ac.ic.wlgitbridge.snapshot.push.exception.SnapshotPostException;
@ -24,13 +26,13 @@ public class WLBridgedProject {
this.bridgeAPI = bridgeAPI; this.bridgeAPI = bridgeAPI;
} }
public void buildRepository() throws RepositoryNotFoundException, ServiceMayNotContinueException { public void buildRepository(Credential oauth2) throws RepositoryNotFoundException, ServiceMayNotContinueException, ForbiddenException {
bridgeAPI.lockForProject(name); bridgeAPI.lockForProject(name);
try { try {
if (repository.getObjectDatabase().exists()) { if (repository.getObjectDatabase().exists()) {
updateRepositoryFromSnapshots(repository); updateRepositoryFromSnapshots(oauth2, repository);
} else { } else {
buildRepositoryFromScratch(repository); buildRepositoryFromScratch(oauth2, repository);
} }
} catch (RuntimeException e) { } catch (RuntimeException e) {
e.printStackTrace(); e.printStackTrace();
@ -40,9 +42,9 @@ public class WLBridgedProject {
} }
} }
private void updateRepositoryFromSnapshots(Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException { private void updateRepositoryFromSnapshots(Credential oauth2, Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException, ForbiddenException {
try { try {
bridgeAPI.getWritableRepositories(name, repository); bridgeAPI.getWritableRepositories(oauth2, name, repository);
} catch (InvalidProjectException e) { } catch (InvalidProjectException e) {
throw new RepositoryNotFoundException(name); throw new RepositoryNotFoundException(name);
} catch (SnapshotPostException e) { } catch (SnapshotPostException e) {
@ -54,8 +56,8 @@ public class WLBridgedProject {
} }
} }
private void buildRepositoryFromScratch(Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException { private void buildRepositoryFromScratch(Credential oauth2, Repository repository) throws RepositoryNotFoundException, ServiceMayNotContinueException, ForbiddenException {
if (!bridgeAPI.repositoryExists(name)) { if (!bridgeAPI.repositoryExists(oauth2, name)) {
throw new RepositoryNotFoundException(name); throw new RepositoryNotFoundException(name);
} }
try { try {
@ -63,7 +65,7 @@ public class WLBridgedProject {
} catch (IOException e) { } catch (IOException e) {
throw new ServiceMayNotContinueException(e); throw new ServiceMayNotContinueException(e);
} }
updateRepositoryFromSnapshots(repository); updateRepositoryFromSnapshots(oauth2, repository);
} }
} }

View file

@ -1,5 +1,7 @@
package uk.ac.ic.wlgitbridge.data; package uk.ac.ic.wlgitbridge.data;
import com.google.api.client.auth.oauth2.Credential;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest; import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocRequest;
import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocResult; import uk.ac.ic.wlgitbridge.snapshot.getdoc.GetDocResult;
@ -17,17 +19,17 @@ import java.util.*;
*/ */
public class SnapshotFetcher { public class SnapshotFetcher {
public LinkedList<Snapshot> getSnapshotsForProjectAfterVersion(String projectName, int version) throws FailedConnectionException, SnapshotPostException { public LinkedList<Snapshot> getSnapshotsForProjectAfterVersion(Credential oauth2, String projectName, int version) throws FailedConnectionException, SnapshotPostException, ForbiddenException {
List<SnapshotInfo> snapshotInfos = getSnapshotInfosAfterVersion(projectName, version); List<SnapshotInfo> snapshotInfos = getSnapshotInfosAfterVersion(oauth2, projectName, version);
List<SnapshotData> snapshotDatas = getMatchingSnapshotData(projectName, snapshotInfos); List<SnapshotData> snapshotDatas = getMatchingSnapshotData(oauth2, projectName, snapshotInfos);
LinkedList<Snapshot> snapshots = combine(snapshotInfos, snapshotDatas); LinkedList<Snapshot> snapshots = combine(snapshotInfos, snapshotDatas);
return snapshots; return snapshots;
} }
private List<SnapshotInfo> getSnapshotInfosAfterVersion(String projectName, int version) throws FailedConnectionException, SnapshotPostException { private List<SnapshotInfo> getSnapshotInfosAfterVersion(Credential oauth2, String projectName, int version) throws FailedConnectionException, SnapshotPostException, ForbiddenException {
SortedSet<SnapshotInfo> versions = new TreeSet<SnapshotInfo>(); SortedSet<SnapshotInfo> versions = new TreeSet<SnapshotInfo>();
GetDocRequest getDoc = new GetDocRequest(projectName); GetDocRequest getDoc = new GetDocRequest(oauth2, projectName);
GetSavedVersRequest getSavedVers = new GetSavedVersRequest(projectName); GetSavedVersRequest getSavedVers = new GetSavedVersRequest(oauth2, projectName);
getDoc.request(); getDoc.request();
getSavedVers.request(); getSavedVers.request();
GetDocResult latestDoc = getDoc.getResult(); GetDocResult latestDoc = getDoc.getResult();
@ -44,8 +46,8 @@ public class SnapshotFetcher {
return new LinkedList<SnapshotInfo>(versions); return new LinkedList<SnapshotInfo>(versions);
} }
private List<SnapshotData> getMatchingSnapshotData(String projectName, List<SnapshotInfo> snapshotInfos) throws FailedConnectionException { private List<SnapshotData> getMatchingSnapshotData(Credential oauth2, String projectName, List<SnapshotInfo> snapshotInfos) throws FailedConnectionException, ForbiddenException {
List<GetForVersionRequest> firedRequests = fireDataRequests(projectName, snapshotInfos); List<GetForVersionRequest> firedRequests = fireDataRequests(oauth2, projectName, snapshotInfos);
List<SnapshotData> snapshotDataList = new LinkedList<SnapshotData>(); List<SnapshotData> snapshotDataList = new LinkedList<SnapshotData>();
for (GetForVersionRequest fired : firedRequests) { for (GetForVersionRequest fired : firedRequests) {
snapshotDataList.add(fired.getResult().getSnapshotData()); snapshotDataList.add(fired.getResult().getSnapshotData());
@ -53,10 +55,10 @@ public class SnapshotFetcher {
return snapshotDataList; return snapshotDataList;
} }
private List<GetForVersionRequest> fireDataRequests(String projectName, List<SnapshotInfo> snapshotInfos) { private List<GetForVersionRequest> fireDataRequests(Credential oauth2, String projectName, List<SnapshotInfo> snapshotInfos) {
List<GetForVersionRequest> requests = new LinkedList<GetForVersionRequest>(); List<GetForVersionRequest> requests = new LinkedList<GetForVersionRequest>();
for (SnapshotInfo snapshotInfo : snapshotInfos) { for (SnapshotInfo snapshotInfo : snapshotInfos) {
GetForVersionRequest request = new GetForVersionRequest(projectName, snapshotInfo.getVersionId()); GetForVersionRequest request = new GetForVersionRequest(oauth2, projectName, snapshotInfo.getVersionId());
requests.add(request); requests.add(request);
request.request(); request.request();
} }

View file

@ -1,11 +1,13 @@
package uk.ac.ic.wlgitbridge.data; package uk.ac.ic.wlgitbridge.data;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.ServiceMayNotContinueException; import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import uk.ac.ic.wlgitbridge.bridge.WLBridgedProject; import uk.ac.ic.wlgitbridge.bridge.WLBridgedProject;
import uk.ac.ic.wlgitbridge.bridge.BridgeAPI; import uk.ac.ic.wlgitbridge.bridge.BridgeAPI;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.util.Util; import uk.ac.ic.wlgitbridge.util.Util;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.InternalErrorException; import uk.ac.ic.wlgitbridge.snapshot.push.exception.InternalErrorException;
@ -23,8 +25,8 @@ public class SnapshotRepositoryBuilder {
this.bridgeAPI = bridgeAPI; this.bridgeAPI = bridgeAPI;
} }
public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory) throws RepositoryNotFoundException, ServiceMayNotContinueException { public Repository getRepositoryWithNameAtRootDirectory(String name, File rootDirectory, Credential oauth2) throws RepositoryNotFoundException, ServiceMayNotContinueException, ForbiddenException {
if (!bridgeAPI.repositoryExists(name)) { if (!bridgeAPI.repositoryExists(oauth2, name)) {
throw new RepositoryNotFoundException(name); throw new RepositoryNotFoundException(name);
} }
File repositoryDirectory = new File(rootDirectory, name); File repositoryDirectory = new File(rootDirectory, name);
@ -32,7 +34,7 @@ public class SnapshotRepositoryBuilder {
Repository repository = null; Repository repository = null;
try { try {
repository = new FileRepositoryBuilder().setWorkTree(repositoryDirectory).build(); repository = new FileRepositoryBuilder().setWorkTree(repositoryDirectory).build();
new WLBridgedProject(repository, name, bridgeAPI).buildRepository(); new WLBridgedProject(repository, name, bridgeAPI).buildRepository(oauth2);
} catch (IOException e) { } catch (IOException e) {
Util.printStackTrace(e); Util.printStackTrace(e);
throw new ServiceMayNotContinueException(new InternalErrorException().getDescriptionLines().get(0)); throw new ServiceMayNotContinueException(new InternalErrorException().getDescriptionLines().get(0));

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.data.model; package uk.ac.ic.wlgitbridge.data.model;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
@ -10,6 +11,7 @@ import uk.ac.ic.wlgitbridge.data.filestore.GitDirectoryContents;
import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory; import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
import uk.ac.ic.wlgitbridge.data.filestore.RawFile; import uk.ac.ic.wlgitbridge.data.filestore.RawFile;
import uk.ac.ic.wlgitbridge.data.model.db.PersistentStore; import uk.ac.ic.wlgitbridge.data.model.db.PersistentStore;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment; import uk.ac.ic.wlgitbridge.snapshot.getforversion.SnapshotAttachment;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.SnapshotPostException; import uk.ac.ic.wlgitbridge.snapshot.push.exception.SnapshotPostException;
@ -40,8 +42,8 @@ public class DataStore {
resourceFetcher = new ResourceFetcher(persistentStore); resourceFetcher = new ResourceFetcher(persistentStore);
} }
public void updateProjectWithName(String name, Repository repository) throws IOException, SnapshotPostException, GitAPIException { public void updateProjectWithName(Credential oauth2, String name, Repository repository) throws IOException, SnapshotPostException, GitAPIException, ForbiddenException {
LinkedList<Snapshot> snapshots = snapshotFetcher.getSnapshotsForProjectAfterVersion(name, persistentStore.getLatestVersionForProject(name)); LinkedList<Snapshot> snapshots = snapshotFetcher.getSnapshotsForProjectAfterVersion(oauth2, name, persistentStore.getLatestVersionForProject(name));
if (!snapshots.isEmpty()) { if (!snapshots.isEmpty()) {
persistentStore.setLatestVersionForProject(name, snapshots.getLast().getVersionID()); persistentStore.setLatestVersionForProject(name, snapshots.getLast().getVersionID());
} }

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.git.handler; package uk.ac.ic.wlgitbridge.git.handler;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory; import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
@ -7,6 +8,7 @@ import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import uk.ac.ic.wlgitbridge.bridge.BridgeAPI; import uk.ac.ic.wlgitbridge.bridge.BridgeAPI;
import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook; import uk.ac.ic.wlgitbridge.git.handler.hook.WriteLatexPutHook;
import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
import uk.ac.ic.wlgitbridge.util.Util; import uk.ac.ic.wlgitbridge.util.Util;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -25,12 +27,13 @@ public class WLReceivePackFactory implements ReceivePackFactory<HttpServletReque
@Override @Override
public ReceivePack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException { public ReceivePack create(HttpServletRequest httpServletRequest, Repository repository) throws ServiceNotEnabledException, ServiceNotAuthorizedException {
Credential oauth2 = (Credential) httpServletRequest.getAttribute(Oauth2Filter.ATTRIBUTE_KEY);
ReceivePack receivePack = new ReceivePack(repository); ReceivePack receivePack = new ReceivePack(repository);
String hostname = Util.getPostbackURL(); String hostname = Util.getPostbackURL();
if (hostname == null) { if (hostname == null) {
hostname = httpServletRequest.getLocalName(); hostname = httpServletRequest.getLocalName();
} }
receivePack.setPreReceiveHook(new WriteLatexPutHook(bridgeAPI, hostname)); receivePack.setPreReceiveHook(new WriteLatexPutHook(bridgeAPI, hostname, oauth2));
return receivePack; return receivePack;
} }

View file

@ -1,13 +1,17 @@
package uk.ac.ic.wlgitbridge.git.handler; package uk.ac.ic.wlgitbridge.git.handler;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException; import org.eclipse.jgit.transport.ServiceMayNotContinueException;
import org.eclipse.jgit.transport.resolver.RepositoryResolver; import org.eclipse.jgit.transport.resolver.RepositoryResolver;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import uk.ac.ic.wlgitbridge.application.config.Oauth2;
import uk.ac.ic.wlgitbridge.data.SnapshotRepositoryBuilder; import uk.ac.ic.wlgitbridge.data.SnapshotRepositoryBuilder;
import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException; import uk.ac.ic.wlgitbridge.git.exception.InvalidRootDirectoryPathException;
import uk.ac.ic.wlgitbridge.server.Oauth2Filter;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.util.Util; import uk.ac.ic.wlgitbridge.util.Util;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -28,8 +32,9 @@ public class WLRepositoryResolver implements RepositoryResolver<HttpServletReque
@Override @Override
public Repository open(HttpServletRequest httpServletRequest, String name) throws RepositoryNotFoundException, ServiceNotAuthorizedException, ServiceNotEnabledException, ServiceMayNotContinueException { public Repository open(HttpServletRequest httpServletRequest, String name) throws RepositoryNotFoundException, ServiceNotAuthorizedException, ServiceNotEnabledException, ServiceMayNotContinueException {
Credential oauth2 = (Credential) httpServletRequest.getAttribute(Oauth2Filter.ATTRIBUTE_KEY);
try { try {
return snapshotRepositoryBuilder.getRepositoryWithNameAtRootDirectory(Util.removeAllSuffixes(name, "/", ".git"), rootGitDirectory); return snapshotRepositoryBuilder.getRepositoryWithNameAtRootDirectory(Util.removeAllSuffixes(name, "/", ".git"), rootGitDirectory, oauth2);
} catch (RepositoryNotFoundException e) { } catch (RepositoryNotFoundException e) {
Util.printStackTrace(e); Util.printStackTrace(e);
throw e; throw e;
@ -44,6 +49,8 @@ public class WLRepositoryResolver implements RepositoryResolver<HttpServletReque
} catch (RuntimeException e) { } catch (RuntimeException e) {
Util.printStackTrace(e); Util.printStackTrace(e);
throw new ServiceMayNotContinueException(e); throw new ServiceMayNotContinueException(e);
} catch (ForbiddenException e) {
throw new ServiceNotAuthorizedException();
} }
} }

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.git.handler.hook; package uk.ac.ic.wlgitbridge.git.handler.hook;
import com.google.api.client.auth.oauth2.Credential;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.PreReceiveHook; import org.eclipse.jgit.transport.PreReceiveHook;
import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.transport.ReceiveCommand;
@ -10,6 +11,7 @@ import uk.ac.ic.wlgitbridge.git.handler.hook.exception.ForcedPushException;
import uk.ac.ic.wlgitbridge.git.handler.hook.exception.WrongBranchException; import uk.ac.ic.wlgitbridge.git.handler.hook.exception.WrongBranchException;
import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory; import uk.ac.ic.wlgitbridge.data.filestore.RawDirectory;
import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker; import uk.ac.ic.wlgitbridge.git.util.RepositoryObjectTreeWalker;
import uk.ac.ic.wlgitbridge.snapshot.base.ForbiddenException;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.InternalErrorException; import uk.ac.ic.wlgitbridge.snapshot.push.exception.InternalErrorException;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.OutOfDateException; import uk.ac.ic.wlgitbridge.snapshot.push.exception.OutOfDateException;
@ -26,17 +28,19 @@ public class WriteLatexPutHook implements PreReceiveHook {
private final BridgeAPI bridgeAPI; private final BridgeAPI bridgeAPI;
private final String hostname; private final String hostname;
private final Credential oauth2;
public WriteLatexPutHook(BridgeAPI bridgeAPI, String hostname) { public WriteLatexPutHook(BridgeAPI bridgeAPI, String hostname, Credential oauth2) {
this.bridgeAPI = bridgeAPI; this.bridgeAPI = bridgeAPI;
this.hostname = hostname; this.hostname = hostname;
this.oauth2 = oauth2;
} }
@Override @Override
public void onPreReceive(ReceivePack receivePack, Collection<ReceiveCommand> receiveCommands) { public void onPreReceive(ReceivePack receivePack, Collection<ReceiveCommand> receiveCommands) {
for (ReceiveCommand receiveCommand : receiveCommands) { for (ReceiveCommand receiveCommand : receiveCommands) {
try { try {
handleReceiveCommand(receivePack.getRepository(), receiveCommand); handleReceiveCommand(oauth2, receivePack.getRepository(), receiveCommand);
} catch (IOException e) { } catch (IOException e) {
receivePack.sendError(e.getMessage()); receivePack.sendError(e.getMessage());
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, e.getMessage()); receiveCommand.setResult(Result.REJECTED_OTHER_REASON, e.getMessage());
@ -60,14 +64,17 @@ public class WriteLatexPutHook implements PreReceiveHook {
receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message); receiveCommand.setResult(Result.REJECTED_OTHER_REASON, message);
} }
private void handleReceiveCommand(Repository repository, ReceiveCommand receiveCommand) throws IOException, SnapshotPostException, FailedConnectionException { private void handleReceiveCommand(Credential oauth2, Repository repository, ReceiveCommand receiveCommand) throws IOException, SnapshotPostException, ForbiddenException {
checkBranch(receiveCommand); checkBranch(receiveCommand);
checkForcedPush(receiveCommand); checkForcedPush(receiveCommand);
bridgeAPI.putDirectoryContentsToProjectWithName(repository.getWorkTree().getName(), bridgeAPI.putDirectoryContentsToProjectWithName(
oauth2,
repository.getWorkTree().getName(),
getPushedDirectoryContents(repository, getPushedDirectoryContents(repository,
receiveCommand), receiveCommand),
getOldDirectoryContents(repository), getOldDirectoryContents(repository),
hostname); hostname
);
} }
private void checkBranch(ReceiveCommand receiveCommand) throws WrongBranchException { private void checkBranch(ReceiveCommand receiveCommand) throws WrongBranchException {

View file

@ -4,6 +4,7 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -15,9 +16,12 @@ import uk.ac.ic.wlgitbridge.git.servlet.WLGitServlet;
import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest; import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
import uk.ac.ic.wlgitbridge.util.Util; import uk.ac.ic.wlgitbridge.util.Util;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import java.io.File; import java.io.File;
import java.net.BindException; import java.net.BindException;
import java.util.EnumSet;
/** /**
* Created by Winston on 02/11/14. * Created by Winston on 02/11/14.
@ -36,23 +40,13 @@ public class GitBridgeServer {
private String rootGitDirectoryPath; private String rootGitDirectoryPath;
private String apiBaseURL; private String apiBaseURL;
/** public GitBridgeServer(Config config) throws ServletException, InvalidRootDirectoryPathException {
* Constructs an instance of the server.
* @param port the port number to listen on
* @param rootGitDirectoryPath the root directory path containing the git repositories
* @throws ServletException if the servlet throws an exception
*/
private GitBridgeServer(final int port, String rootGitDirectoryPath) throws ServletException, InvalidRootDirectoryPathException {
Log.setLog(new NullLogger()); Log.setLog(new NullLogger());
this.port = port; this.port = config.getPort();
this.rootGitDirectoryPath = rootGitDirectoryPath; this.rootGitDirectoryPath = config.getRootGitDirectory();
bridgeAPI = new BridgeAPI(rootGitDirectoryPath); bridgeAPI = new BridgeAPI(rootGitDirectoryPath);
jettyServer = new Server(port); jettyServer = new Server(port);
configureJettyServer(); configureJettyServer(config);
}
public GitBridgeServer(Config config) throws ServletException, InvalidRootDirectoryPathException {
this(config.getPort(), config.getRootGitDirectory());
SnapshotAPIRequest.setBasicAuth(config.getUsername(), config.getPassword()); SnapshotAPIRequest.setBasicAuth(config.getUsername(), config.getPassword());
apiBaseURL = config.getAPIBaseURL(); apiBaseURL = config.getAPIBaseURL();
SnapshotAPIRequest.setBaseURL(apiBaseURL); SnapshotAPIRequest.setBaseURL(apiBaseURL);
@ -87,18 +81,22 @@ public class GitBridgeServer {
} }
} }
private void configureJettyServer() throws ServletException, InvalidRootDirectoryPathException { private void configureJettyServer(Config config) throws ServletException, InvalidRootDirectoryPathException {
HandlerCollection handlers = new HandlerCollection(); HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] { handlers.setHandlers(new Handler[] {
initResourceHandler(), initResourceHandler(),
new PostbackHandler(bridgeAPI), new PostbackHandler(bridgeAPI),
initGitHandler() initGitHandler(config)
}); });
jettyServer.setHandler(handlers); jettyServer.setHandler(handlers);
} }
private Handler initGitHandler() throws ServletException, InvalidRootDirectoryPathException { private Handler initGitHandler(Config config) throws ServletException, InvalidRootDirectoryPathException {
final ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); final ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
if (config.isUsingOauth2()) {
Filter filter = new Oauth2Filter(config.getOauth2());
servletContextHandler.addFilter(new FilterHolder(filter), "/*", EnumSet.of(DispatcherType.REQUEST));
}
servletContextHandler.setContextPath("/"); servletContextHandler.setContextPath("/");
servletContextHandler.addServlet( servletContextHandler.addServlet(
new ServletHolder( new ServletHolder(

View file

@ -0,0 +1,100 @@
package uk.ac.ic.wlgitbridge.server;
import com.google.api.client.auth.oauth2.*;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.server.Request;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.ic.wlgitbridge.application.config.Oauth2;
import uk.ac.ic.wlgitbridge.util.Instance;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;
/**
* Created by winston on 25/10/15.
*/
public class Oauth2Filter implements Filter {
public static final String ATTRIBUTE_KEY = "oauth2";
private final Oauth2 oauth2;
public Oauth2Filter(Oauth2 oauth2) {
this.oauth2 = oauth2;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String authHeader = request.getHeader("Authorization");
if (authHeader != null) {
StringTokenizer st = new StringTokenizer(authHeader);
if (st.hasMoreTokens()) {
String basic = st.nextToken();
if (basic.equalsIgnoreCase("Basic")) {
try {
String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
String[] split = credentials.split(":");
if (split.length == 2) {
String username = split[0];
String password = split[1];
String accessToken = null;
try {
accessToken = new PasswordTokenRequest(Instance.httpTransport, Instance.jsonFactory, new GenericUrl(oauth2.getOauth2Server() + "/oauth/token"), username, password)
.setClientAuthentication(new ClientParametersAuthentication(oauth2.getOauth2ClientID(), oauth2.getOauth2ClientSecret()))
.execute().getAccessToken();
} catch (TokenResponseException e) {
unauthorized(response, "bad credentials");
return;
}
final Credential cred = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod())
.build();
cred.setAccessToken(accessToken);
servletRequest.setAttribute(ATTRIBUTE_KEY, cred);
filterChain.doFilter(servletRequest, servletResponse);
} else {
unauthorized(response, "Invalid authentication token");
}
} catch (UnsupportedEncodingException e) {
throw new Error("Couldn't retrieve authentication", e);
}
}
}
} else {
unauthorized(response);
}
}
@Override
public void destroy() {
}
private void unauthorized(HttpServletResponse response, String message) throws IOException {
response.setHeader("WWW-Authenticate", "Basic realm=\"Git Bridge\"");
response.sendError(401, message);
}
private void unauthorized(HttpServletResponse response) throws IOException {
unauthorized(response, "Unauthorized");
}
}

View file

@ -0,0 +1,7 @@
package uk.ac.ic.wlgitbridge.snapshot.base;
/**
* Created by winston on 25/10/15.
*/
public class ForbiddenException extends Throwable {
}

View file

@ -1,15 +1,18 @@
package uk.ac.ic.wlgitbridge.snapshot.base; package uk.ac.ic.wlgitbridge.snapshot.base;
import com.google.api.client.http.*;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
import com.ning.http.client.Realm;
import com.ning.http.client.Response; import com.ning.http.client.Response;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.util.Instance;
import uk.ac.ic.wlgitbridge.util.Util; import uk.ac.ic.wlgitbridge.util.Util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -22,12 +25,10 @@ public abstract class Request<T extends Result> {
private final String url; private final String url;
private Future<T> future; private Future<HttpResponse> future;
private boolean error;
public Request(String url) { public Request(String url) {
this.url = url; this.url = url;
error = false;
} }
public void request() { public void request() {
@ -43,54 +44,65 @@ public abstract class Request<T extends Result> {
} }
} }
public T getResult() throws FailedConnectionException { public T getResult() throws FailedConnectionException, ForbiddenException {
if (error) {
throw new FailedConnectionException();
}
try { try {
return future.get(); HttpResponse response = future.get();
Util.sout(response.getStatusCode() + " " + response.getStatusMessage() + " (" + response.getHeaders().getContentLength() + "B) -> " + url);
JsonElement json = new Gson().fromJson(response.parseAsString(), JsonElement.class);
return parseResponse(json);
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new FailedConnectionException(); throw new FailedConnectionException();
} catch (ExecutionException e) { } catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof HttpResponseException && ((HttpResponseException) cause).getStatusCode() == HttpServletResponse.SC_FORBIDDEN) {
throw new ForbiddenException();
} else {
throw new FailedConnectionException();
}
} catch (IOException e) {
Util.serr("Failed to parse JSON");
e.printStackTrace();
throw new FailedConnectionException(); throw new FailedConnectionException();
} }
} }
protected abstract HTTPMethod httpMethod(); protected abstract HTTPMethod httpMethod();
protected abstract Realm buildRequestRealm();
protected void onBeforeRequest(HttpRequest request) throws IOException {
}
protected abstract T parseResponse(JsonElement json) throws FailedConnectionException; protected abstract T parseResponse(JsonElement json) throws FailedConnectionException;
protected String getPostBody() { protected String getPostBody() {
return ""; return null;
} }
private void performGetRequest() { private void performGetRequest() {
Util.sout("GET -> " + url); Util.sout("GET -> " + url);
request(httpClient.prepareGet(url)); try {
HttpRequest request = Instance.httpRequestFactory.buildGetRequest(new GenericUrl(url));
request(request);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
} }
private void performPostRequest() { private void performPostRequest() {
Util.sout("POST -> " + url); Util.sout("POST -> " + url);
request(httpClient.preparePost(url).setBody(getPostBody()).setHeader("Content-Type", "application/json")); try {
HttpRequest request = Instance.httpRequestFactory.buildPostRequest(new GenericUrl(url), new ByteArrayContent("application/json", getPostBody().getBytes()));
request(request);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
} }
private void request(BoundRequestBuilder boundRequestBuilder) { private void request(HttpRequest request) throws IOException {
future = boundRequestBuilder.setRealm(buildRequestRealm()).execute(new AsyncCompletionHandler<T>() { onBeforeRequest(request);
future = request.executeAsync();
@Override
public T onCompleted(Response response) throws Exception {
String body = response.getResponseBody();
Util.sout(response.getStatusCode() + " " + response.getStatusText() + " (" + body.length() + "B) -> " + url);
return parseResponse(new Gson().fromJson(body, JsonElement.class));
}
@Override
public void onThrowable(Throwable t) {
Util.printStackTrace(t);
error = true;
}
});
} }
} }

View file

@ -1,7 +1,13 @@
package uk.ac.ic.wlgitbridge.snapshot.base; package uk.ac.ic.wlgitbridge.snapshot.base;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.BasicAuthentication;
import com.google.api.client.http.HttpExecuteInterceptor;
import com.google.api.client.http.HttpRequest;
import com.ning.http.client.Realm; import com.ning.http.client.Realm;
import java.io.IOException;
/** /**
* Created by Winston on 06/11/14. * Created by Winston on 06/11/14.
*/ */
@ -12,17 +18,26 @@ public abstract class SnapshotAPIRequest<T extends Result> extends Request<T> {
private static String BASE_URL; private static String BASE_URL;
public SnapshotAPIRequest(String projectName, String apiCall) { private final Credential oauth2;
public SnapshotAPIRequest(String projectName, String apiCall, Credential oauth2) {
super(BASE_URL + projectName + apiCall); super(BASE_URL + projectName + apiCall);
this.oauth2 = oauth2;
} }
protected Realm buildRequestRealm() { @Override
return new Realm.RealmBuilder() protected void onBeforeRequest(HttpRequest request) throws IOException {
.setPrincipal(USERNAME) request.setInterceptor(new HttpExecuteInterceptor() {
.setPassword(PASSWORD)
.setUsePreemptiveAuth(true) @Override
.setScheme(Realm.AuthScheme.BASIC) public void intercept(HttpRequest request) throws IOException {
.build(); new BasicAuthentication(USERNAME, PASSWORD).intercept(request);
if (oauth2 != null) {
oauth2.intercept(request);
}
}
});
} }
public static void setBasicAuth(String username, String password) { public static void setBasicAuth(String username, String password) {

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.snapshot.getdoc; package uk.ac.ic.wlgitbridge.snapshot.getdoc;
import com.google.api.client.auth.oauth2.Credential;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod; import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod;
import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest; import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
@ -12,8 +13,8 @@ public class GetDocRequest extends SnapshotAPIRequest<GetDocResult> {
public static final String API_CALL = ""; public static final String API_CALL = "";
public GetDocRequest(String projectName) { public GetDocRequest(Credential oauth2, String projectName) {
super(projectName, API_CALL); super(projectName, API_CALL, oauth2);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.snapshot.getforversion; package uk.ac.ic.wlgitbridge.snapshot.getforversion;
import com.google.api.client.auth.oauth2.Credential;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod; import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod;
import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest; import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
@ -14,8 +15,8 @@ public class GetForVersionRequest extends SnapshotAPIRequest<GetForVersionResult
private int versionID; private int versionID;
public GetForVersionRequest(String projectName, int versionID) { public GetForVersionRequest(Credential oauth2, String projectName, int versionID) {
super(projectName, API_CALL + "/" + versionID); super(projectName, API_CALL + "/" + versionID, oauth2);
this.versionID = versionID; this.versionID = versionID;
} }

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.snapshot.getsavedvers; package uk.ac.ic.wlgitbridge.snapshot.getsavedvers;
import com.google.api.client.auth.oauth2.Credential;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest; import uk.ac.ic.wlgitbridge.snapshot.base.SnapshotAPIRequest;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException; import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
@ -12,8 +13,8 @@ public class GetSavedVersRequest extends SnapshotAPIRequest<GetSavedVersResult>
public static final String API_CALL = "/saved_vers"; public static final String API_CALL = "/saved_vers";
public GetSavedVersRequest(String projectName) { public GetSavedVersRequest(Credential oauth2, String projectName) {
super(projectName, API_CALL); super(projectName, API_CALL, oauth2);
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package uk.ac.ic.wlgitbridge.snapshot.push; package uk.ac.ic.wlgitbridge.snapshot.push;
import com.google.api.client.auth.oauth2.Credential;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import uk.ac.ic.wlgitbridge.data.CandidateSnapshot; import uk.ac.ic.wlgitbridge.data.CandidateSnapshot;
import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod; import uk.ac.ic.wlgitbridge.snapshot.base.HTTPMethod;
@ -16,8 +17,8 @@ public class PushRequest extends SnapshotAPIRequest<PushResult> {
private final CandidateSnapshot candidateSnapshot; private final CandidateSnapshot candidateSnapshot;
private final String postbackKey; private final String postbackKey;
public PushRequest(CandidateSnapshot candidateSnapshot, String postbackKey) { public PushRequest(Credential oauth2, CandidateSnapshot candidateSnapshot, String postbackKey) {
super(candidateSnapshot.getProjectName(), API_CALL); super(candidateSnapshot.getProjectName(), API_CALL, oauth2);
this.candidateSnapshot = candidateSnapshot; this.candidateSnapshot = candidateSnapshot;
this.postbackKey = postbackKey; this.postbackKey = postbackKey;
} }

View file

@ -0,0 +1,18 @@
package uk.ac.ic.wlgitbridge.util;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
/**
* Created by winston on 25/10/15.
*/
public class Instance {
public static final HttpTransport httpTransport = new NetHttpTransport();
public static final HttpRequestFactory httpRequestFactory = httpTransport.createRequestFactory();
public static final JsonFactory jsonFactory = new GsonFactory();
}