Commit ea8f1e4d authored by Ricki Hirner's avatar Ricki Hirner

Change authentication restriction to domains instead of host names

parent 62ac4921
Pipeline #5716811 passed with stage
in 4 minutes and 40 seconds
......@@ -48,6 +48,7 @@ android {
dependencies {
compile 'com.android.support:support-annotations:25.+'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.squareup.okhttp3:okhttp:3.5.0'
provided 'org.projectlombok:lombok:1.16.12'
......
......@@ -8,6 +8,9 @@
package at.bitfire.dav4android;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
......@@ -16,7 +19,6 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.NonNull;
import okhttp3.Authenticator;
import okhttp3.Interceptor;
import okhttp3.Request;
......@@ -27,7 +29,7 @@ import okio.Buffer;
import okio.ByteString;
/**
* Handler to manage authentication against a given service (may be limited to one host).
* Handler to manage authentication against a given service (may be limited to one domain).
* There's no domain-based cache, because the same user name and password will be used for
* all requests.
*
......@@ -41,7 +43,10 @@ public class BasicDigestAuthHandler implements Authenticator, Interceptor {
HEADER_AUTHENTICATE = "WWW-Authenticate",
HEADER_AUTHORIZATION = "Authorization";
final String host, username, password;
/** Authenticate only against hosts ending with this domain (may be null, which means no restriction) */
final String domain;
final String username, password;
// cached authentication schemes
HttpUtils.AuthScheme basicAuth, digestAuth;
......@@ -51,17 +56,20 @@ public class BasicDigestAuthHandler implements Authenticator, Interceptor {
static final AtomicInteger nonceCount = new AtomicInteger(1);
public BasicDigestAuthHandler(String host, String username, String password) {
this.host = host;
public BasicDigestAuthHandler(@Nullable String domain, @NonNull String username, @NonNull String password) {
this.domain = domain;
this.username = username;
this.password = password;
}
protected Request authenticateRequest(Request request, Response response) {
if (host != null && !request.url().host().equalsIgnoreCase(host)) {
Constants.log.warning("Not authenticating against " + host + " for security reasons!");
return null;
protected Request authenticateRequest(@NonNull Request request, @Nullable Response response) {
if (domain != null) {
final String host = request.url().host();
if (!domain.equalsIgnoreCase(UrlUtils.hostToDomain(host))) {
Constants.log.warning("Not authenticating against " + host + " because it doesn't belong to " + domain);
return null;
}
}
if (response == null) {
......
package at.bitfire.dav4android;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import java.net.URI;
import java.net.URISyntaxException;
......@@ -7,7 +12,7 @@ import okhttp3.HttpUrl;
public class UrlUtils {
public static boolean equals(HttpUrl url1, HttpUrl url2) {
public static boolean equals(@NonNull HttpUrl url1, @NonNull HttpUrl url2) {
// if okhttp thinks the two URLs are equal, they're in any case
// (and it's a simple String comparison)
if (url1.equals(url2))
......@@ -23,7 +28,22 @@ public class UrlUtils {
}
}
public static HttpUrl omitTrailingSlash(HttpUrl url) {
public static String hostToDomain(@Nullable String host) {
if (host == null)
return null;
// remove optional dot at end
host = StringUtils.removeEnd(host, ".");
// split into labels
String labels[] = StringUtils.split(host, '.');
if (labels.length >= 2) {
return labels[labels.length - 2] + "." + labels[labels.length - 1];
} else
return host;
}
public static HttpUrl omitTrailingSlash(@NonNull HttpUrl url) {
int idxLast = url.pathSize() - 1;
boolean hasTrailingSlash = "".equals(url.pathSegments().get(idxLast));
......@@ -33,7 +53,7 @@ public class UrlUtils {
return url;
}
public static HttpUrl withTrailingSlash(HttpUrl url) {
public static HttpUrl withTrailingSlash(@NonNull HttpUrl url) {
int idxLast = url.pathSize() - 1;
boolean hasTrailingSlash = "".equals(url.pathSegments().get(idxLast));
......
......@@ -6,6 +6,7 @@ import okhttp3.HttpUrl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class UrlUtilsTest {
......@@ -21,6 +22,22 @@ public class UrlUtilsTest {
assertFalse(UrlUtils.equals(HttpUrl.parse("http://host/resource"), HttpUrl.parse("http://host:81/resource")));
}
@Test
public void testHostToDomain() {
assertNull(UrlUtils.hostToDomain(null));
assertEquals("", UrlUtils.hostToDomain("."));
assertEquals("com", UrlUtils.hostToDomain("com"));
assertEquals("com", UrlUtils.hostToDomain("com."));
assertEquals("example.com", UrlUtils.hostToDomain("example.com"));
assertEquals("example.com", UrlUtils.hostToDomain("example.com."));
assertEquals("example.com", UrlUtils.hostToDomain(".example.com"));
assertEquals("example.com", UrlUtils.hostToDomain(".example.com."));
assertEquals("example.com", UrlUtils.hostToDomain("host.example.com"));
assertEquals("example.com", UrlUtils.hostToDomain("host.example.com."));
assertEquals("example.com", UrlUtils.hostToDomain("sub.host.example.com"));
assertEquals("example.com", UrlUtils.hostToDomain("sub.host.example.com."));
}
@Test
public void testOmitTrailingSlash() {
assertEquals(HttpUrl.parse("http://host/resource"), UrlUtils.omitTrailingSlash(HttpUrl.parse("http://host/resource")));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment