You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@lucene.apache.org by janhoy <gi...@git.apache.org> on 2018/03/23 16:36:14 UTC

[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

GitHub user janhoy opened a pull request:

    https://github.com/apache/lucene-solr/pull/343

    SOLR-12121: JWT Token authentication plugin

    First version. Still some TODO and NOCOMMIT. Lacks some end-to-end tests etc.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/cominvent/lucene-solr solr12121-jwt-auth

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/lucene-solr/pull/343.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #343
    
----
commit 2d3a7f4112509c9581d97c36a088715bd0aebca4
Author: Jan Høydahl <ja...@...>
Date:   2018-03-23T16:34:50Z

    SOLR-12121: JWT Token authentication plugin

----


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r241698617
  
    --- Diff: solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java ---
    @@ -0,0 +1,214 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.solr.security;
    +
    +import java.io.BufferedReader;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.OutputStream;
    +import java.net.HttpURLConnection;
    +import java.net.URL;
    +import java.nio.charset.StandardCharsets;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.stream.Collectors;
    +
    +import org.apache.http.Header;
    +import org.apache.http.HttpException;
    +import org.apache.http.HttpHeaders;
    +import org.apache.http.HttpRequest;
    +import org.apache.http.HttpRequestInterceptor;
    +import org.apache.http.entity.ContentType;
    +import org.apache.http.protocol.HttpContext;
    +import org.apache.solr.client.solrj.impl.HttpClientUtil;
    +import org.apache.solr.cloud.SolrCloudAuthTestCase;
    +import org.apache.solr.common.util.Pair;
    +import org.jose4j.jwk.PublicJsonWebKey;
    +import org.jose4j.jwk.RsaJsonWebKey;
    +import org.jose4j.jws.AlgorithmIdentifiers;
    +import org.jose4j.jws.JsonWebSignature;
    +import org.jose4j.jwt.JwtClaims;
    +import org.junit.AfterClass;
    +import org.junit.Before;
    +import org.junit.BeforeClass;
    +import org.junit.Test;
    +
    +/**
    + * Validate that JWT token authentication works in a real cluster.
    + * TODO: Test also using SolrJ as client. But that requires a way to set Authorization header on request, see SOLR-13070
    + */
    +public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
    +  protected static final int NUM_SERVERS = 2;
    +  protected static final int NUM_SHARDS = 2;
    +  protected static final int REPLICATION_FACTOR = 1;
    +  private static final String COLLECTION = "jwtColl";
    +  private static String jwtTestToken;
    +  private static String baseUrl;
    +  private static AtomicInteger jwtInterceptCount = new AtomicInteger();
    +  private static AtomicInteger pkiInterceptCount = new AtomicInteger();
    +  private static final CountInterceptor interceptor = new CountInterceptor();
    +
    +  @BeforeClass
    +  public static void setupClass() throws Exception {
    +    configureCluster(NUM_SERVERS)// nodes
    +        .withSecurityJson(TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security.json"))
    +        .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
    +        .configure();
    +    baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
    +
    +    String jwkJSON = "{\n" +
    +        "  \"kty\": \"RSA\",\n" +
    +        "  \"d\": \"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n" +
    +        "  \"e\": \"AQAB\",\n" +
    +        "  \"use\": \"sig\",\n" +
    +        "  \"kid\": \"test\",\n" +
    +        "  \"alg\": \"RS256\",\n" +
    +        "  \"n\": \"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n" +
    +        "}";
    +
    +    PublicJsonWebKey jwk = RsaJsonWebKey.Factory.newPublicJwk(jwkJSON);
    +    JwtClaims claims = JWTAuthPluginTest.generateClaims();
    +    JsonWebSignature jws = new JsonWebSignature();
    +    jws.setPayload(claims.toJson());
    +    jws.setKey(jwk.getPrivateKey());
    +    jws.setKeyIdHeaderValue(jwk.getKeyId());
    +    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    +
    +    jwtTestToken = jws.getCompactSerialization();
    +
    +    HttpClientUtil.removeRequestInterceptor(interceptor);
    +    HttpClientUtil.addRequestInterceptor(interceptor);
    +    
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @AfterClass
    +  public static void tearDownClass() throws Exception {
    +    System.clearProperty("java.security.auth.login.config");
    --- End diff --
    
    Removed


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r241402568
  
    --- Diff: solr/core/src/java/org/apache/solr/security/JWTPrincipalWithUserRoles.java ---
    @@ -0,0 +1,71 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +package org.apache.solr.security;
    +
    +import java.util.Map;
    +import java.util.Objects;
    +import java.util.Set;
    +
    +import org.apache.http.util.Args;
    +
    +/**
    + * JWT principal that contains username, token, claims and a list of roles the user has, 
    + * so one can keep track of user-role mappings in an Identity Server external to Solr and 
    + * pass the information to Solr in a signed JWT token. The role information can then be used to authorize
    + * requests without the need to maintain or lookup what roles each user belongs to.
    + */
    +public class JWTPrincipalWithUserRoles extends JWTPrincipal implements VerifiedUserRoles {
    +  private final Set<String> roles;
    +
    +  public JWTPrincipalWithUserRoles(final String username, String token, Map<String,Object> claims, Set<String> roles) {
    +    super(username, token, claims);
    +    Args.notNull(roles, "User roles");
    +    this.roles = roles;
    +  }
    +
    +  /**
    +   * Gets the list of roles
    +   */
    +  @Override
    +  public Set<String> getVerifiedRoles() {
    +    return roles;
    +  }
    +
    +  @Override
    +  public boolean equals(Object o) {
    +    if (!(o instanceof JWTPrincipalWithUserRoles))
    +      return false;
    +    JWTPrincipalWithUserRoles that = (JWTPrincipalWithUserRoles) o;
    +    return super.equals(o) && roles.equals(that.roles);
    +  }
    +
    +  @Override
    +  public int hashCode() {
    +    return Objects.hash(username, token, claims, roles);
    +  }
    +
    +  @Override
    +  public String toString() {
    +    return "JWTPrincipalWithUserRoles{" +
    +        "username='" + username + '\'' +
    +        ", token='" + token + '\'' +
    --- End diff --
    
    Same as above - redact token


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r241403280
  
    --- Diff: solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java ---
    @@ -0,0 +1,214 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.solr.security;
    +
    +import java.io.BufferedReader;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.OutputStream;
    +import java.net.HttpURLConnection;
    +import java.net.URL;
    +import java.nio.charset.StandardCharsets;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.stream.Collectors;
    +
    +import org.apache.http.Header;
    +import org.apache.http.HttpException;
    +import org.apache.http.HttpHeaders;
    +import org.apache.http.HttpRequest;
    +import org.apache.http.HttpRequestInterceptor;
    +import org.apache.http.entity.ContentType;
    +import org.apache.http.protocol.HttpContext;
    +import org.apache.solr.client.solrj.impl.HttpClientUtil;
    +import org.apache.solr.cloud.SolrCloudAuthTestCase;
    +import org.apache.solr.common.util.Pair;
    +import org.jose4j.jwk.PublicJsonWebKey;
    +import org.jose4j.jwk.RsaJsonWebKey;
    +import org.jose4j.jws.AlgorithmIdentifiers;
    +import org.jose4j.jws.JsonWebSignature;
    +import org.jose4j.jwt.JwtClaims;
    +import org.junit.AfterClass;
    +import org.junit.Before;
    +import org.junit.BeforeClass;
    +import org.junit.Test;
    +
    +/**
    + * Validate that JWT token authentication works in a real cluster.
    + * TODO: Test also using SolrJ as client. But that requires a way to set Authorization header on request, see SOLR-13070
    + */
    +public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
    +  protected static final int NUM_SERVERS = 2;
    +  protected static final int NUM_SHARDS = 2;
    +  protected static final int REPLICATION_FACTOR = 1;
    +  private static final String COLLECTION = "jwtColl";
    +  private static String jwtTestToken;
    +  private static String baseUrl;
    +  private static AtomicInteger jwtInterceptCount = new AtomicInteger();
    +  private static AtomicInteger pkiInterceptCount = new AtomicInteger();
    +  private static final CountInterceptor interceptor = new CountInterceptor();
    +
    +  @BeforeClass
    +  public static void setupClass() throws Exception {
    +    configureCluster(NUM_SERVERS)// nodes
    +        .withSecurityJson(TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security.json"))
    +        .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
    +        .configure();
    +    baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
    +
    +    String jwkJSON = "{\n" +
    +        "  \"kty\": \"RSA\",\n" +
    +        "  \"d\": \"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n" +
    +        "  \"e\": \"AQAB\",\n" +
    +        "  \"use\": \"sig\",\n" +
    +        "  \"kid\": \"test\",\n" +
    +        "  \"alg\": \"RS256\",\n" +
    +        "  \"n\": \"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n" +
    +        "}";
    +
    +    PublicJsonWebKey jwk = RsaJsonWebKey.Factory.newPublicJwk(jwkJSON);
    +    JwtClaims claims = JWTAuthPluginTest.generateClaims();
    +    JsonWebSignature jws = new JsonWebSignature();
    +    jws.setPayload(claims.toJson());
    +    jws.setKey(jwk.getPrivateKey());
    +    jws.setKeyIdHeaderValue(jwk.getKeyId());
    +    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    +
    +    jwtTestToken = jws.getCompactSerialization();
    +
    +    HttpClientUtil.removeRequestInterceptor(interceptor);
    +    HttpClientUtil.addRequestInterceptor(interceptor);
    +    
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @AfterClass
    +  public static void tearDownClass() throws Exception {
    +    System.clearProperty("java.security.auth.login.config");
    +    shutdownCluster();
    +  }
    +
    +  @Before
    +  public void before() throws IOException, InterruptedException, TimeoutException {
    +    jwtInterceptCount.set(0);
    +    pkiInterceptCount.set(0);
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @Test(expected = IOException.class)
    +  public void infoRequestWithoutToken() throws Exception {
    +    get(baseUrl + "admin/info/system", null);
    +  }
    +
    +  @Test
    +  public void infoRequestWithToken() throws IOException {
    +    Pair<String,Integer> result = get(baseUrl + "admin/info/system", jwtTestToken);
    +    assertEquals(Integer.valueOf(200), result.second());
    +    verifyInterRequestHeaderCounts(0,0);
    +  }
    +
    +  @Test
    +  public void testMetrics() {
    +    // NOCOMMIT: Metrics tests, with failing requests etc
    --- End diff --
    
    Add lots of exceptional tests here to trigger metrics counts


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r243600574
  
    --- Diff: solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java ---
    @@ -0,0 +1,214 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.solr.security;
    +
    +import java.io.BufferedReader;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.OutputStream;
    +import java.net.HttpURLConnection;
    +import java.net.URL;
    +import java.nio.charset.StandardCharsets;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.stream.Collectors;
    +
    +import org.apache.http.Header;
    +import org.apache.http.HttpException;
    +import org.apache.http.HttpHeaders;
    +import org.apache.http.HttpRequest;
    +import org.apache.http.HttpRequestInterceptor;
    +import org.apache.http.entity.ContentType;
    +import org.apache.http.protocol.HttpContext;
    +import org.apache.solr.client.solrj.impl.HttpClientUtil;
    +import org.apache.solr.cloud.SolrCloudAuthTestCase;
    +import org.apache.solr.common.util.Pair;
    +import org.jose4j.jwk.PublicJsonWebKey;
    +import org.jose4j.jwk.RsaJsonWebKey;
    +import org.jose4j.jws.AlgorithmIdentifiers;
    +import org.jose4j.jws.JsonWebSignature;
    +import org.jose4j.jwt.JwtClaims;
    +import org.junit.AfterClass;
    +import org.junit.Before;
    +import org.junit.BeforeClass;
    +import org.junit.Test;
    +
    +/**
    + * Validate that JWT token authentication works in a real cluster.
    + * TODO: Test also using SolrJ as client. But that requires a way to set Authorization header on request, see SOLR-13070
    + */
    +public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
    +  protected static final int NUM_SERVERS = 2;
    +  protected static final int NUM_SHARDS = 2;
    +  protected static final int REPLICATION_FACTOR = 1;
    +  private static final String COLLECTION = "jwtColl";
    +  private static String jwtTestToken;
    +  private static String baseUrl;
    +  private static AtomicInteger jwtInterceptCount = new AtomicInteger();
    +  private static AtomicInteger pkiInterceptCount = new AtomicInteger();
    +  private static final CountInterceptor interceptor = new CountInterceptor();
    +
    +  @BeforeClass
    +  public static void setupClass() throws Exception {
    +    configureCluster(NUM_SERVERS)// nodes
    +        .withSecurityJson(TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security.json"))
    +        .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
    +        .configure();
    +    baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
    +
    +    String jwkJSON = "{\n" +
    +        "  \"kty\": \"RSA\",\n" +
    +        "  \"d\": \"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n" +
    +        "  \"e\": \"AQAB\",\n" +
    +        "  \"use\": \"sig\",\n" +
    +        "  \"kid\": \"test\",\n" +
    +        "  \"alg\": \"RS256\",\n" +
    +        "  \"n\": \"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n" +
    +        "}";
    +
    +    PublicJsonWebKey jwk = RsaJsonWebKey.Factory.newPublicJwk(jwkJSON);
    +    JwtClaims claims = JWTAuthPluginTest.generateClaims();
    +    JsonWebSignature jws = new JsonWebSignature();
    +    jws.setPayload(claims.toJson());
    +    jws.setKey(jwk.getPrivateKey());
    +    jws.setKeyIdHeaderValue(jwk.getKeyId());
    +    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    +
    +    jwtTestToken = jws.getCompactSerialization();
    +
    +    HttpClientUtil.removeRequestInterceptor(interceptor);
    +    HttpClientUtil.addRequestInterceptor(interceptor);
    +    
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @AfterClass
    +  public static void tearDownClass() throws Exception {
    +    System.clearProperty("java.security.auth.login.config");
    +    shutdownCluster();
    +  }
    +
    +  @Before
    +  public void before() throws IOException, InterruptedException, TimeoutException {
    +    jwtInterceptCount.set(0);
    +    pkiInterceptCount.set(0);
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @Test(expected = IOException.class)
    +  public void infoRequestWithoutToken() throws Exception {
    +    get(baseUrl + "admin/info/system", null);
    +  }
    +
    +  @Test
    +  public void infoRequestWithToken() throws IOException {
    +    Pair<String,Integer> result = get(baseUrl + "admin/info/system", jwtTestToken);
    +    assertEquals(Integer.valueOf(200), result.second());
    +    verifyInterRequestHeaderCounts(0,0);
    +  }
    +
    +  @Test
    +  public void testMetrics() {
    +    // NOCOMMIT: Metrics tests, with failing requests etc
    --- End diff --
    
    Added more tests


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r241401404
  
    --- Diff: solr/core/src/java/org/apache/solr/security/JWTPrincipal.java ---
    @@ -0,0 +1,88 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +package org.apache.solr.security;
    +
    +import java.io.Serializable;
    +import java.security.Principal;
    +import java.util.Map;
    +import java.util.Objects;
    +
    +import org.apache.http.util.Args;
    +
    +/**
    + * Principal object that carries JWT token and claims for authenticated user.
    + */
    +public class JWTPrincipal implements Principal, Serializable {
    +  private static final long serialVersionUID = 4144666467522831388L;
    +  final String username;
    +  String token;
    +  Map<String,Object> claims;
    +
    +  /**
    +   * User principal with user name as well as one or more roles that he/she belong to
    +   * @param username string with user name for user
    +   * @param token compact string representation of JWT token
    +   * @param claims list of verified JWT claims as a map
    +   */
    +  public JWTPrincipal(final String username, String token, Map<String,Object> claims) {
    +    super();
    +    Args.notNull(username, "User name");
    +    Args.notNull(token, "JWT token");
    +    Args.notNull(claims, "JWT claims");
    +    this.token = token;
    +    this.claims = claims;
    +    this.username = username;
    +  }
    +
    +  @Override
    +  public String getName() {
    +    return this.username;
    +  }
    +
    +  public String getToken() {
    +    return token;
    +  }
    +
    +  public Map<String, Object> getClaims() {
    +    return claims;
    +  }
    +
    +  @Override
    +  public boolean equals(Object o) {
    +    if (this == o) return true;
    +    if (o == null || getClass() != o.getClass()) return false;
    +    JWTPrincipal that = (JWTPrincipal) o;
    +    return Objects.equals(username, that.username) &&
    +        Objects.equals(token, that.token) &&
    +        Objects.equals(claims, that.claims);
    +  }
    +
    +  @Override
    +  public int hashCode() {
    +    return Objects.hash(username, token, claims);
    +  }
    +
    +  @Override
    +  public String toString() {
    +    return "JWTPrincipal{" +
    +        "username='" + username + '\'' +
    +        ", token='" + token + '\'' +
    --- End diff --
    
    Redact token in toString to avoid leak to logs etc


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org


[GitHub] lucene-solr pull request #343: SOLR-12121: JWT Token authentication plugin

Posted by janhoy <gi...@git.apache.org>.
Github user janhoy commented on a diff in the pull request:

    https://github.com/apache/lucene-solr/pull/343#discussion_r241403119
  
    --- Diff: solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java ---
    @@ -0,0 +1,214 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one or more
    + * contributor license agreements.  See the NOTICE file distributed with
    + * this work for additional information regarding copyright ownership.
    + * The ASF licenses this file to You under the Apache License, Version 2.0
    + * (the "License"); you may not use this file except in compliance with
    + * the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.solr.security;
    +
    +import java.io.BufferedReader;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.OutputStream;
    +import java.net.HttpURLConnection;
    +import java.net.URL;
    +import java.nio.charset.StandardCharsets;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.stream.Collectors;
    +
    +import org.apache.http.Header;
    +import org.apache.http.HttpException;
    +import org.apache.http.HttpHeaders;
    +import org.apache.http.HttpRequest;
    +import org.apache.http.HttpRequestInterceptor;
    +import org.apache.http.entity.ContentType;
    +import org.apache.http.protocol.HttpContext;
    +import org.apache.solr.client.solrj.impl.HttpClientUtil;
    +import org.apache.solr.cloud.SolrCloudAuthTestCase;
    +import org.apache.solr.common.util.Pair;
    +import org.jose4j.jwk.PublicJsonWebKey;
    +import org.jose4j.jwk.RsaJsonWebKey;
    +import org.jose4j.jws.AlgorithmIdentifiers;
    +import org.jose4j.jws.JsonWebSignature;
    +import org.jose4j.jwt.JwtClaims;
    +import org.junit.AfterClass;
    +import org.junit.Before;
    +import org.junit.BeforeClass;
    +import org.junit.Test;
    +
    +/**
    + * Validate that JWT token authentication works in a real cluster.
    + * TODO: Test also using SolrJ as client. But that requires a way to set Authorization header on request, see SOLR-13070
    + */
    +public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
    +  protected static final int NUM_SERVERS = 2;
    +  protected static final int NUM_SHARDS = 2;
    +  protected static final int REPLICATION_FACTOR = 1;
    +  private static final String COLLECTION = "jwtColl";
    +  private static String jwtTestToken;
    +  private static String baseUrl;
    +  private static AtomicInteger jwtInterceptCount = new AtomicInteger();
    +  private static AtomicInteger pkiInterceptCount = new AtomicInteger();
    +  private static final CountInterceptor interceptor = new CountInterceptor();
    +
    +  @BeforeClass
    +  public static void setupClass() throws Exception {
    +    configureCluster(NUM_SERVERS)// nodes
    +        .withSecurityJson(TEST_PATH().resolve("security").resolve("jwt_plugin_jwk_security.json"))
    +        .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
    +        .configure();
    +    baseUrl = cluster.getRandomJetty(random()).getBaseUrl().toString();
    +
    +    String jwkJSON = "{\n" +
    +        "  \"kty\": \"RSA\",\n" +
    +        "  \"d\": \"i6pyv2z3o-MlYytWsOr3IE1olu2RXZBzjPRBNgWAP1TlLNaphHEvH5aHhe_CtBAastgFFMuP29CFhaL3_tGczkvWJkSveZQN2AHWHgRShKgoSVMspkhOt3Ghha4CvpnZ9BnQzVHnaBnHDTTTfVgXz7P1ZNBhQY4URG61DKIF-JSSClyh1xKuMoJX0lILXDYGGcjVTZL_hci4IXPPTpOJHV51-pxuO7WU5M9252UYoiYyCJ56ai8N49aKIMsqhdGuO4aWUwsGIW4oQpjtce5eEojCprYl-9rDhTwLAFoBtjy6LvkqlR2Ae5dKZYpStljBjK8PJrBvWZjXAEMDdQ8PuQ\",\n" +
    +        "  \"e\": \"AQAB\",\n" +
    +        "  \"use\": \"sig\",\n" +
    +        "  \"kid\": \"test\",\n" +
    +        "  \"alg\": \"RS256\",\n" +
    +        "  \"n\": \"jeyrvOaZrmKWjyNXt0myAc_pJ1hNt3aRupExJEx1ewPaL9J9HFgSCjMrYxCB1ETO1NDyZ3nSgjZis-jHHDqBxBjRdq_t1E2rkGFaYbxAyKt220Pwgme_SFTB9MXVrFQGkKyjmQeVmOmV6zM3KK8uMdKQJ4aoKmwBcF5Zg7EZdDcKOFgpgva1Jq-FlEsaJ2xrYDYo3KnGcOHIt9_0NQeLsqZbeWYLxYni7uROFncXYV5FhSJCeR4A_rrbwlaCydGxE0ToC_9HNYibUHlkJjqyUhAgORCbNS8JLCJH8NUi5sDdIawK9GTSyvsJXZ-QHqo4cMUuxWV5AJtaRGghuMUfqQ\"\n" +
    +        "}";
    +
    +    PublicJsonWebKey jwk = RsaJsonWebKey.Factory.newPublicJwk(jwkJSON);
    +    JwtClaims claims = JWTAuthPluginTest.generateClaims();
    +    JsonWebSignature jws = new JsonWebSignature();
    +    jws.setPayload(claims.toJson());
    +    jws.setKey(jwk.getPrivateKey());
    +    jws.setKeyIdHeaderValue(jwk.getKeyId());
    +    jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
    +
    +    jwtTestToken = jws.getCompactSerialization();
    +
    +    HttpClientUtil.removeRequestInterceptor(interceptor);
    +    HttpClientUtil.addRequestInterceptor(interceptor);
    +    
    +    cluster.waitForAllNodes(10);
    +  }
    +
    +  @AfterClass
    +  public static void tearDownClass() throws Exception {
    +    System.clearProperty("java.security.auth.login.config");
    --- End diff --
    
    Unused?


---

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@lucene.apache.org
For additional commands, e-mail: dev-help@lucene.apache.org