Skip to content

Commit

Permalink
Merge pull request #906 from virtualcell/905-restore-webapp-auth
Browse files Browse the repository at this point in the history
reenable browser auth with cookies
  • Loading branch information
jcschaff authored Jun 15, 2023
2 parents 4067ca2 + d169463 commit 27d3af5
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 38 deletions.
5 changes: 5 additions & 0 deletions docker/swarm/README_stack_on_mac.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ popd
pushd ../../pythonProject/vcell-opt
poetry install
popd

pushd ../../vcell-cli-utils
poetry install
popd

```

2. Build and push Docker and Singularity containers (without building clients)
Expand Down
9 changes: 6 additions & 3 deletions docker/swarm/localconfig_realslurm_oracle.sh
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,14 @@ VCELL_REPO_NAMESPACE=$VCELL_REPO_NAMESPACE
VCELL_SECRETS_DIR=${HOME}/vcellkeys_oracle
VCELL_SIMDATADIR_ARCHIVE_EXTERNAL=/share/apps/vcell12/users
VCELL_SIMDATADIR_ARCHIVE_INTERNAL=/share/apps/vcell12/users
VCELL_SIMDATADIR_ARCHIVE_HOST=/Volumes/vcell-2/users
VCELL_SIMDATADIR_ARCHIVE_HOST=/Volumes/vcell-1/users
VCELL_SIMDATADIR_ARCHIVE_HOST_ORIG=/Volumes/vcell-2/users
VCELL_SIMDATADIR_EXTERNAL=/share/apps/vcell3/users
VCELL_SIMDATADIR_HOST=/Volumes/vcell/users
VCELL_SIMDATADIR_SECONDARY_EXTERNAL=/share/apps/vcell10/users
VCELL_SIMDATADIR_SECONDARY_HOST=/Volumes/vcell-1/users
VCELL_SIMDATADIR_SECONDARY_EXTERNAL=/share/apps/vcell3/users
VCELL_SIMDATADIR_SECONDARY_HOST=/Volumes/vcell/users
VCELL_SIMDATADIR_SECONDARY_EXTERNAL_ORIG=/share/apps/vcell7/users
VCELL_SIMDATADIR_SECONDARY_HOST_ORIG=/Volumes/vcell-1/users
VCELL_SIMDATADIR_PARALLEL_EXTERNAL=/share/apps/vcell3parallel
VCELL_SITE_CAMEL=${_site_camel}
VCELL_SITE=$VCELL_SITE
Expand Down
32 changes: 25 additions & 7 deletions vcell-api/src/main/java/org/vcell/rest/UserVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jose4j.jwt.MalformedClaimException;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.ext.crypto.CookieAuthenticator;
import org.restlet.security.Verifier;
import org.vcell.auth.JWTUtils;
import org.vcell.rest.users.UnverifiedUser;
import org.vcell.util.DataAccessException;
import org.vcell.util.ObjectNotFoundException;
Expand Down Expand Up @@ -156,24 +159,39 @@ public int verify(Request request, Response response) {
}

public AuthenticationStatus verify(ChallengeResponse challengeResponse) {
if (challengeResponse != null && challengeResponse.getScheme().equals(ChallengeScheme.HTTP_OAUTH_BEARER) && challengeResponse.getRawValue()!=null){
if (challengeResponse != null && challengeResponse.getScheme().equals(ChallengeScheme.HTTP_OAUTH_BEARER) && challengeResponse.getRawValue() != null) {
try {
ApiAccessToken accessToken = getApiAccessToken(challengeResponse.getRawValue());
if (accessToken==null){
if (accessToken == null) {
return AuthenticationStatus.invalid;
}else if (accessToken.isExpired()){
} else if (accessToken.isExpired()) {
return AuthenticationStatus.stale;
}else if (accessToken.getStatus()==AccessTokenStatus.invalidated){
} else if (accessToken.getStatus() == AccessTokenStatus.invalidated) {
return AuthenticationStatus.invalid;
}else{
} else {
return AuthenticationStatus.valid;
}
}catch (Exception e){
} catch (Exception e) {
lg.error(e.getMessage(), e);
return AuthenticationStatus.invalid;
}
}else{
} else if (challengeResponse != null && challengeResponse.getScheme().equals(ChallengeScheme.HTTP_COOKIE) && challengeResponse.getSecret() != null) {
String token = new String(challengeResponse.getSecret());
try {
boolean valid = JWTUtils.verifyJWS(token);
if (valid) {
return AuthenticationStatus.valid;
} else {
return AuthenticationStatus.invalid;
}
} catch (MalformedClaimException e) {
lg.error("token was not valid", e);
return AuthenticationStatus.invalid;
}
} else if (challengeResponse == null) {
return AuthenticationStatus.missing;
} else {
return AuthenticationStatus.invalid;
}
}

Expand Down
52 changes: 35 additions & 17 deletions vcell-api/src/main/java/org/vcell/rest/VCellApiApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -252,16 +252,7 @@ public Restlet createInboundRoot() {
* :"38442201","mathModelBranchId"
* :"38442202","mathModelName":"tempMath77"}}]
*/


// Attach a guard to secure access to user parts of the api

boolean bAuthOptional = true;
ChallengeAuthenticator guard = new ChallengeAuthenticator(
getContext(), bAuthOptional, ChallengeScheme.HTTP_OAUTH_BEARER, "testRealm");
TokenBasedVerifier verifier = new TokenBasedVerifier();
guard.setVerifier(verifier);

String ROOT_URI = javascriptDir.toURI().toString();
String WEBAPP_URI = new File(javascriptDir.getParentFile(),"webapp").toURI().toString();
System.out.println("using uri="+ROOT_URI+" for scripts directory");
Expand Down Expand Up @@ -333,10 +324,33 @@ public void handle(Request request, Response response) {
}

});

guard.setNext(rootRouter);

return guard;

// Attach an auth bearer guard to secure access to user parts of the api via
boolean bAuthOptional = true;
ChallengeAuthenticator bearerTokenGuard = new ChallengeAuthenticator(
getContext(), bAuthOptional, ChallengeScheme.HTTP_OAUTH_BEARER, "testRealm");
TokenBasedVerifier verifier = new TokenBasedVerifier();
bearerTokenGuard.setMultiAuthenticating(false); // if it is already authenticated via cookies, then don't authenticate again
bearerTokenGuard.setVerifier(verifier);

// Attach a cookie based Basic auth guard to secure access to browser access.
boolean bCookieOptional = true;
final VCellCookieAuthenticator cookieAuthenticator = new VCellCookieAuthenticator(
this, bCookieOptional, "My cookie realm", "MyExtraSecretKey".getBytes());
cookieAuthenticator.setMultiAuthenticating(false);
cookieAuthenticator.setLoginPath("/"+LOGIN);
cookieAuthenticator.setLogoutPath("/"+LOGOUT);
cookieAuthenticator.setCookieName("org.vcell.auth");
cookieAuthenticator.setLoginFormPath("/"+LOGINFORM);
cookieAuthenticator.setIdentifierFormName(IDENTIFIER_FORMNAME);
cookieAuthenticator.setSecretFormName(SECRET_FORMNAME);
cookieAuthenticator.setRedirectQueryName(REDIRECTURL_FORMNAME);
cookieAuthenticator.setVerifier(userVerifier);
cookieAuthenticator.setMaxCookieAge(15*60); // 15 minutes (in units of seconds).

bearerTokenGuard.setNext(rootRouter);
cookieAuthenticator.setNext(bearerTokenGuard);
return cookieAuthenticator;
}

public RestDatabaseService getRestDatabaseService() {
Expand Down Expand Up @@ -405,12 +419,16 @@ ApiAccessToken getApiAccessToken(ChallengeResponse response) throws SQLException
if (response==null){
getLogger().log(Level.INFO,"VCellApiApplication.getApiAccessToken(response) - response was null");
return null;
}else if (response.getRawValue()==null){
getLogger().log(Level.INFO,"VCellApiApplication.getApiAccessToken(response) - response.getRawValue() was null");
}else if (response.getSecret() != null) {
ApiAccessToken accessToken = userVerifier.getApiAccessToken(new String(response.getSecret()));
return accessToken;
}else if (response.getRawValue() != null) {
ApiAccessToken accessToken = userVerifier.getApiAccessToken(new String(response.getRawValue()));
return accessToken;
}else{
getLogger().log(Level.INFO,"VCellApiApplication.getApiAccessToken(response) - response.getSecret() and response.getRawValue() were both null");
return null;
}
ApiAccessToken accessToken = userVerifier.getApiAccessToken(new String(response.getRawValue()));
return accessToken;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@
import org.apache.logging.log4j.Logger;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.Cookie;
import org.restlet.data.Form;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.data.*;
import org.restlet.ext.crypto.CookieAuthenticator;
import org.restlet.representation.Representation;
import org.vcell.rest.auth.CustomAuthHelper;
Expand Down Expand Up @@ -57,7 +52,9 @@ protected void login(Request request, Response response) {
request.setChallengeResponse(cr);


getCredentialsCookie(request, response).setMaxAge(0);
CookieSetting crendentialCookie = getCredentialsCookie(request, response);
crendentialCookie.setMaxAge(0);
crendentialCookie.setValue(accessToken.getToken());

getLogger().log(Level.INFO,"MyCookieAuthenticator.login(request,response) - created new accessToken '"+accessToken.getToken()+"' and assignd to ChallengeResponse, redirectURL='"+redirectURL.getValue()+"'");

Expand Down Expand Up @@ -92,6 +89,12 @@ protected int logout(Request request, Response response) {
return super.logout(request, response);
}

@Override
public ChallengeResponse parseCredentials(String cookieValue) {
// increase visibility of this method
return super.parseCredentials(cookieValue);
}

};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.restlet.data.ChallengeResponse;
import org.restlet.security.Verifier;
import org.vcell.auth.JWTUtils;
import org.vcell.rest.VCellApiApplication;

import java.util.Arrays;
import java.util.List;
Expand All @@ -20,10 +21,11 @@ public class TokenBasedVerifier implements Verifier {
@Override
public int verify(Request request, Response response) {
List<String> noAuthPaths = Arrays.asList(
"/access_token",
"/swversion",
"/newuser",
"/lostpassword");
"/"+VCellApiApplication.ACCESSTOKENRESOURCE,
"/"+VCellApiApplication.SWVERSION,
"/"+VCellApiApplication.NEWUSER,
"/"+VCellApiApplication.LOSTPASSWORD,
"/"+ VCellApiApplication.LOGINFORM);
if (noAuthPaths.contains(request.getResourceRef().getPath())){
return Verifier.RESULT_VALID;
}
Expand Down

0 comments on commit 27d3af5

Please sign in to comment.