Skip to content

Commit

Permalink
Merge pull request #13 from kbase/dev-new_client
Browse files Browse the repository at this point in the history
Add backwards compatibility shim
  • Loading branch information
MrCreosote authored Apr 17, 2024
2 parents 881552f + 070b23f commit 94c8b8d
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 1 deletion.
120 changes: 120 additions & 0 deletions src/main/java/us/kbase/auth/AuthConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package us.kbase.auth;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

/** The configuration class for {@link ConfigurableAuthService}.
*
* Changes to the config have no effect after {@link ConfigurableAuthService} is instantiated.
*
* @author [email protected]
*
*/
public class AuthConfig {

private static final String DEFAULT_KBASE_AUTH_SERVER_URL =
"https://ci.kbase.us/services/auth/";

private static final String LEGACY_PATH = "api/legacy/KBase/";
private static final String LOGIN_LOC = "Sessions/Login/";

private URI authServerURL;
private boolean allowInsecureURLs = false;

/** Get the default authorization URL.
* @return the default authorization URL.
*/
public static URL getDefaultAuthURL() {
try {
return new URL(DEFAULT_KBASE_AUTH_SERVER_URL);
} catch (MalformedURLException e) {
throw new RuntimeException("The impossible just happened");
}
}

/**
* Create a configuration object with default settings.
*/
public AuthConfig() {
try {
authServerURL = new URI(DEFAULT_KBASE_AUTH_SERVER_URL);
} catch (URISyntaxException use) {
throw new RuntimeException(
"This cannot occur. Please check with your local deity for an explanation.");
}
}

/** Set the URL of the KBase authorization server. Note that to maintain
* compatibility with previous versions of this client, URLs ending in
* Sessions/Login, api/legacy/KBase/, or api/legacy/KBase/Sessions/Login
* with or without trailing slashes will have that portion of the URL removed.
* @param authServer the URL of the KBase authorization server.
* @return this
* @throws URISyntaxException if the URL is not a valid URI. In general
* this should never happen.
*/
public AuthConfig withKBaseAuthServerURL(URL authServer)
throws URISyntaxException {
if (authServer == null) {
throw new NullPointerException("authServer cannot be null");
}
if (!authServer.toString().endsWith("/")) {
try {
authServer = new URL(authServer.toString() + "/");
} catch (MalformedURLException e) {
throw new RuntimeException("This can't happen", e);
}
}
authServer = stripURLSuffix(authServer, LOGIN_LOC);
authServer = stripURLSuffix(authServer, LEGACY_PATH);
authServerURL = authServer.toURI();
return this;
}

private URL stripURLSuffix(URL rui, final String suffix) {
if (rui.getPath().endsWith(suffix)) {
final int index = rui.toString().lastIndexOf(suffix);
try {
rui = new URL(rui.toString().substring(0, index));
} catch (MalformedURLException e) {
throw new RuntimeException(
"The impossible just occured. Congratulations.", e);
}
}
return rui;
}

/** Allow insecure http URLs rather than https URLs. Only use this setting
* for tests, never in production.
*
* When using insecure URLs, you must call this method *before*
* initializing the auth client.
* @param insecure true to allow insecure URLs.
* @return this
*/
public AuthConfig withAllowInsecureURLs(final boolean insecure) {
this.allowInsecureURLs = insecure;
return this;
}

/** Returns the configured KBase authorization service URL.
* @return the authorization service URL.
*/
public URL getAuthServerURL() {
try {
return authServerURL.toURL();
} catch (MalformedURLException e) {
throw new RuntimeException("This should never happen");
}
}

/** Returns true if insecure URLs are allowed, false otherwise.
* @return whether insecure URLs are allowed.
*/
public boolean isInsecureURLsAllowed() {
return allowInsecureURLs;
}

}
89 changes: 89 additions & 0 deletions src/main/java/us/kbase/auth/ConfigurableAuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package us.kbase.auth;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;

import us.kbase.auth.client.AuthClient;

/**
* This is a shim around the {@link AuthClient} for backwards compatibility purposes.
*
* Only one instance of a client should be created per application if at all possible.
*
* @author wjriehl
* @author [email protected]
*/
public class ConfigurableAuthService {

private final AuthClient client;

/** Create an authorization service client with the default configuration.
* @throws IOException if an IO error occurs.
*/
public ConfigurableAuthService() throws IOException {
this(new AuthConfig());
}

/** Create an authorization service client with a custom configuration.
* @param config the configuration for the auth client.
* @throws IOException if an IO error occurs.
*/
public ConfigurableAuthService(final AuthConfig config) throws IOException {
if (config == null) {
throw new NullPointerException("config cannot be null");
}
if (!config.isInsecureURLsAllowed() &&
!"https".equals(config.getAuthServerURL().getProtocol())) {
throw new IllegalArgumentException(String.format(
"The URL %s is insecure and insecure URLs are not allowed",
config.getAuthServerURL()));
}
try {
client = AuthClient.from(config.getAuthServerURL().toURI());
} catch (AuthException e) {
// can't break backwards compatibility by throwing AuthException
throw new IOException(e.getMessage(), e);
} catch (URISyntaxException e) {
throw new RuntimeException("this should be impossible - checked in AuthConfig", e);
}
}

/** Get the auth client underlying this client.
* @return the client.
*/
public AuthClient getClient() {
return client;
}

/**
* Checks whether strings are a valid user names.
* @param usernames the usernames
* @param token a valid token
* @return a mapping of username to validity.
* @throws AuthException if the credentials are invalid
* @throws IOException if there is a problem communicating with the server.
* @throws IllegalArgumentException if a username is invalid.
*/
public Map<String, Boolean> isValidUserName(
final List<String> usernames,
final AuthToken token)
throws IOException, AuthException {
return client.isValidUserName(usernames, token.getToken());
}

/**
* Validates a token and returns a validated token.
*
* @param tokenStr the token string to validate.
* @return a validated token
* @throws IOException if there is a problem communicating with the server.
* @throws AuthException if the token is invalid.
*/
public AuthToken validateToken(final String tokenStr)
throws IOException, AuthException {
return client.validateToken(tokenStr);
}

}
7 changes: 7 additions & 0 deletions src/main/java/us/kbase/auth/client/AuthClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ private String readResponse(
}
return restext.toString();
}

/** Get the auth service URI.
* @return the URI.
*/
public URI getURI() {
return rootURI;
}

/** Get the version of the auth server with which this client communicates.
* @return the server version.
Expand Down
1 change: 0 additions & 1 deletion src/main/java/us/kbase/auth/client/cache/TokenCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ class UserDate {
long date;

UserDate(String user) {
super();
this.user = user;
this.date = new Date().getTime();
}
Expand Down
68 changes: 68 additions & 0 deletions src/test/java/us/kbase/test/auth/AuthConfigTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package us.kbase.test.auth;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.net.URL;

import org.junit.Test;

import us.kbase.auth.AuthConfig;
import us.kbase.test.common.TestCommon;

public class AuthConfigTest {

@Test
public void defaultURL() throws Exception {
assertThat("incorrect default URL", AuthConfig.getDefaultAuthURL(),
is(new URL("https://ci.kbase.us/services/auth/")));
}

@Test
public void buildMinimal() throws Exception {
final AuthConfig c = new AuthConfig();

assertThat("incorrect auth URL", c.getAuthServerURL(),
is(new URL("https://ci.kbase.us/services/auth/")));
assertThat("incorrect allow insecure", c.isInsecureURLsAllowed(), is(false));
}

@Test
public void buildMaximal() throws Exception {
final AuthConfig c = new AuthConfig()
.withKBaseAuthServerURL(new URL("https://vegtableexcitement.com"))
.withAllowInsecureURLs(true);

assertThat("incorrect auth URL", c.getAuthServerURL(),
is(new URL("https://vegtableexcitement.com/")));
assertThat("incorrect allow insecure", c.isInsecureURLsAllowed(), is(true));
}

@Test
public void buildAndStripURLs() throws Exception {
// this one seems unlikely to be seen in the wild
buildAndStripURLs("https://ci.kbase.us/services/auth/Sessions/Login");
buildAndStripURLs("https://ci.kbase.us/services/auth/api/legacy/KBase/");
buildAndStripURLs("https://ci.kbase.us/services/auth/api/legacy/KBase/Sessions/Login");
}

private void buildAndStripURLs(final String url) throws Exception {
final AuthConfig c = new AuthConfig().withKBaseAuthServerURL(new URL(url));

assertThat("incorrect auth URL", c.getAuthServerURL(),
is(new URL("https://ci.kbase.us/services/auth/")));
}

@Test
public void withKBaseAuthServerURLFail() throws Exception {
try {
new AuthConfig().withKBaseAuthServerURL(null);
fail("expected exception");
} catch (Exception got) {
TestCommon.assertExceptionCorrect(
got, new NullPointerException("authServer cannot be null"));
}
}

}
Loading

0 comments on commit 94c8b8d

Please sign in to comment.