Skip to content

Commit

Permalink
Merge pull request #42 from CleverCloud/supportAuthViaQueryParamForWS
Browse files Browse the repository at this point in the history
also get token from queryparam when http query
  • Loading branch information
KannarFr authored Nov 15, 2023
2 parents 329b128 + 4b5f29c commit 7b9bc5d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 3 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<!-- test dependencies -->
<assertj-core.version>3.14.0</assertj-core.version>
<junit.version>4.13.1</junit.version>
<mockito.version>5.6.0</mockito.version>
</properties>

<licenses>
Expand Down Expand Up @@ -218,5 +219,12 @@
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
import org.apache.pulsar.broker.authentication.AuthenticationProvider;
import org.apache.pulsar.broker.authentication.AuthenticationProviderToken;
import org.apache.pulsar.broker.authentication.*;
import org.apache.pulsar.common.api.AuthData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.AuthenticationException;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -147,6 +149,17 @@ public String authenticate(AuthenticationDataSource authData) throws Authenticat
}
}

@Override
public AuthenticationState newAuthState(AuthData authData, SocketAddress remoteAddress, SSLSession sslSession)
throws AuthenticationException {
return new OneStageAuthenticationState(authData, remoteAddress, sslSession, this);
}

@Override
public AuthenticationState newHttpAuthState(HttpServletRequest request) throws AuthenticationException {
return new OneStageAuthenticationState(new HttpServletRequestWrapper(request), this);
}

public static String getBearerValue(AuthenticationDataSource authData) throws AuthenticationException {
if (authData.hasDataFromCommand()) {
// Authenticate Pulsar binary connection
Expand Down Expand Up @@ -201,4 +214,26 @@ public static byte[] hexStringToByteArray(String hex) {
}
return data;
}

private static final class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {
private final HttpServletRequest request;

public HttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}

@Override
public String getHeader(String name) {
// The browser javascript WebSocket client couldn't add the auth param to the request header, use the
// query param `token` to transport the auth token for the browser javascript WebSocket client.
if (name.equals(HTTP_HEADER_NAME) && request.getHeader(HTTP_HEADER_NAME) == null) {
String token = request.getParameter(BISCUIT);
if (token != null) {
return !token.startsWith(HTTP_HEADER_VALUE_PREFIX) ? HTTP_HEADER_VALUE_PREFIX + token : token;
}
}
return super.getHeader(name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import com.clevercloud.biscuit.token.builder.Block;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
import org.apache.pulsar.broker.authentication.AuthenticationState;
import org.hamcrest.core.StringStartsWith;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Properties;
Expand All @@ -22,6 +24,8 @@
import static com.clevercloud.biscuit.token.builder.Utils.s;
import static org.junit.Assert.assertThrows;
import static org.hamcrest.MatcherAssert.*;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

public class AuthenticationProviderBiscuitTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationProviderBiscuitTest.class);
Expand Down Expand Up @@ -106,4 +110,66 @@ public String getCommandData() {

provider.close();
}

@Test
public void testTokenFromHttpParams() throws Exception {
KeyPair root = new KeyPair("D283C7E436D89C544CC2B20C1028A7ADDC18FCED6386A6130465C17B996CD893");

AuthenticationProviderBiscuit provider = new AuthenticationProviderBiscuit();

Properties properties = new Properties();
properties.setProperty(AuthenticationProviderBiscuit.CONF_BISCUIT_PUBLIC_ROOT_KEY, hex(root.public_key().key.getAbyte()));

ServiceConfiguration conf = new ServiceConfiguration();
conf.setProperties(properties);
provider.initialize(conf);

SymbolTable symbols = Biscuit.default_symbol_table();

Block authority_builder = new Block(0, symbols);
authority_builder.add_fact(fact("right", Arrays.asList(s("topic"), s("public"), s("default"), s("test"), s("produce"))));

byte[] seed = {0, 0, 0, 0};
SecureRandom rng = new SecureRandom(seed);
Biscuit b = Biscuit.make(rng, root, Biscuit.default_symbol_table(), authority_builder.build());

HttpServletRequest servletRequest = mock(HttpServletRequest.class);
doReturn(b.serialize_b64url()).when(servletRequest).getParameter("token");
doReturn(null).when(servletRequest).getHeader("Authorization");
doReturn("127.0.0.1").when(servletRequest).getRemoteAddr();
doReturn(0).when(servletRequest).getRemotePort();

AuthenticationState authState = provider.newHttpAuthState(servletRequest);
provider.authenticate(authState.getAuthDataSource());
}

@Test
public void testTokenFromHttpHeaders() throws Exception {
KeyPair root = new KeyPair("D283C7E436D89C544CC2B20C1028A7ADDC18FCED6386A6130465C17B996CD893");

AuthenticationProviderBiscuit provider = new AuthenticationProviderBiscuit();

Properties properties = new Properties();
properties.setProperty(AuthenticationProviderBiscuit.CONF_BISCUIT_PUBLIC_ROOT_KEY, hex(root.public_key().key.getAbyte()));

ServiceConfiguration conf = new ServiceConfiguration();
conf.setProperties(properties);
provider.initialize(conf);

SymbolTable symbols = Biscuit.default_symbol_table();

Block authority_builder = new Block(0, symbols);
authority_builder.add_fact(fact("right", Arrays.asList(s("topic"), s("public"), s("default"), s("test"), s("produce"))));

byte[] seed = {0, 0, 0, 0};
SecureRandom rng = new SecureRandom(seed);
Biscuit b = Biscuit.make(rng, root, Biscuit.default_symbol_table(), authority_builder.build());
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
doReturn("Bearer " + b.serialize_b64url()).when(servletRequest).getHeader("Authorization");
doReturn("127.0.0.1").when(servletRequest).getRemoteAddr();
doReturn(0).when(servletRequest).getRemotePort();

AuthenticationState authState = provider.newHttpAuthState(servletRequest);
provider.authenticate(authState.getAuthDataSource());
}
}

0 comments on commit 7b9bc5d

Please sign in to comment.