Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@
package org.apache.pulsar.broker.authentication;

import java.security.cert.X509Certificate;

import javax.servlet.http.HttpServletRequest;

public class AuthenticationDataHttps extends AuthenticationDataHttp {

protected final X509Certificate[] certificates;

public AuthenticationDataHttps(HttpServletRequest request) {
super(request);
super(new AuthenticationProviderToken.HttpServletRequestWrapper(request));
certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,30 @@
package org.apache.pulsar.broker.authentication;

import static java.nio.charset.StandardCharsets.UTF_8;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.SignatureException;
import io.prometheus.client.Counter;
import io.prometheus.client.Histogram;
import java.io.IOException;
import java.net.SocketAddress;
import java.security.Key;

import java.util.Date;
import java.util.List;
import javax.naming.AuthenticationException;
import javax.net.ssl.SSLSession;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.prometheus.client.Counter;
import io.prometheus.client.Histogram;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.metrics.AuthenticationMetrics;
import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils;
import org.apache.pulsar.common.api.AuthData;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.SignatureException;

public class AuthenticationProviderToken implements AuthenticationProvider {

final static String HTTP_HEADER_NAME = "Authorization";
Expand Down Expand Up @@ -351,4 +348,25 @@ public boolean isExpired() {
return expiration < System.currentTimeMillis();
}
}
public 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(TOKEN);
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 @@ -18,13 +18,13 @@
*/
package org.apache.pulsar.broker.authentication;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;

import com.google.common.collect.Lists;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
Expand All @@ -33,25 +33,23 @@
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.List;
import lombok.Cleanup;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.sql.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import javax.crypto.SecretKey;
import javax.naming.AuthenticationException;

import javax.servlet.http.HttpServletRequest;
import lombok.Cleanup;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils;
import org.apache.pulsar.common.api.AuthData;
Expand Down Expand Up @@ -800,4 +798,55 @@ public String getCommandData() {
assertEquals(subject, SUBJECT);
provider.close();
}

@Test
public void testTokenFromHttpParams() throws Exception {
SecretKey secretKey = AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);

@Cleanup
AuthenticationProviderToken provider = new AuthenticationProviderToken();

Properties properties = new Properties();
properties.setProperty(AuthenticationProviderToken.CONF_TOKEN_SECRET_KEY,
AuthTokenUtils.encodeKeyBase64(secretKey));

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

String token = AuthTokenUtils.createToken(secretKey, SUBJECT, Optional.empty());
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
doReturn(token).when(servletRequest).getParameter("token");
doReturn(null).when(servletRequest).getHeader("Authorization");
doReturn("127.0.0.1").when(servletRequest).getRemoteAddr();
doReturn(0).when(servletRequest).getRemotePort();

AuthenticationDataHttps authenticationDataHttps = new AuthenticationDataHttps(servletRequest);
provider.authenticate(authenticationDataHttps);
}

@Test
public void testTokenFromHttpHeaders() throws Exception {
SecretKey secretKey = AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256);

@Cleanup
AuthenticationProviderToken provider = new AuthenticationProviderToken();

Properties properties = new Properties();
properties.setProperty(AuthenticationProviderToken.CONF_TOKEN_SECRET_KEY,
AuthTokenUtils.encodeKeyBase64(secretKey));

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

String token = AuthTokenUtils.createToken(secretKey, SUBJECT, Optional.empty());
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
doReturn("Bearer " + token).when(servletRequest).getHeader("Authorization");
doReturn("127.0.0.1").when(servletRequest).getRemoteAddr();
doReturn(0).when(servletRequest).getRemotePort();

AuthenticationDataHttps authenticationDataHttps = new AuthenticationDataHttps(servletRequest);
provider.authenticate(authenticationDataHttps);
}
}