Repository: nutch
Updated Branches:
  refs/heads/2.x 9ecdc9be3 -> 75d846cf3


NUTCH-2308 SSL connection test at TestNutchAPI is implemented.


Project: http://git-wip-us.apache.org/repos/asf/nutch/repo
Commit: http://git-wip-us.apache.org/repos/asf/nutch/commit/75d846cf
Tree: http://git-wip-us.apache.org/repos/asf/nutch/tree/75d846cf
Diff: http://git-wip-us.apache.org/repos/asf/nutch/diff/75d846cf

Branch: refs/heads/2.x
Commit: 75d846cf3998faeffa6edf5a7d7fec2d22c8d4d9
Parents: 9ecdc9b
Author: Furkan KAMACI <[email protected]>
Authored: Thu Aug 25 23:54:52 2016 +0300
Committer: Furkan KAMACI <[email protected]>
Committed: Tue Aug 30 19:02:29 2016 +0300

----------------------------------------------------------------------
 conf/nutch-default.xml                          |   4 +-
 src/java/org/apache/nutch/api/NutchServer.java  |  10 +-
 .../nutch/api/resources/AdminResource.java      |   8 +-
 .../nutch/api/resources/ConfigResource.java     |   8 +-
 .../apache/nutch/api/resources/DbResource.java  |   4 +-
 .../apache/nutch/api/resources/JobResource.java |   4 +-
 .../nutch/api/resources/SeedResource.java       |   4 +-
 .../apache/nutch/api/security/SecurityUtil.java | 108 -------------------
 .../nutch/api/security/SecurityUtils.java       | 107 ++++++++++++++++++
 src/test/nutch-site.xml                         |   2 +-
 src/test/nutch-ssl.keystore.jks                 | Bin 2300 -> 2272 bytes
 src/test/nutch.cer                              | Bin 0 -> 921 bytes
 .../nutch/api/AbstractNutchAPITestBase.java     |  89 +++++++++++++--
 src/test/org/apache/nutch/api/TestNutchAPI.java |  33 +++---
 src/test/testTrustKeyStore                      | Bin 0 -> 983 bytes
 15 files changed, 231 insertions(+), 150 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/conf/nutch-default.xml
----------------------------------------------------------------------
diff --git a/conf/nutch-default.xml b/conf/nutch-default.xml
index d2181c5..575ce5d 100644
--- a/conf/nutch-default.xml
+++ b/conf/nutch-default.xml
@@ -1465,10 +1465,10 @@
 
 <property>
   <name>restapi.auth.ssl.storepath</name>
-  <value>etc/nutch-ssl.keystore.jks</value>
+  <value>nutch-ssl.keystore.jks</value>
   <description>
     Key store path for jks file. restapi.auth property should be set to SSL to 
use this property.
-    etc/nutch-ssl.keystore.jks is used for restapi.auth.ssl.storepath as 
default.
+    nutch-ssl.keystore.jks is used for restapi.auth.ssl.storepath as default.
   </description>
 </property>
 

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/NutchServer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/NutchServer.java 
b/src/java/org/apache/nutch/api/NutchServer.java
index e65742d..802bbef 100644
--- a/src/java/org/apache/nutch/api/NutchServer.java
+++ b/src/java/org/apache/nutch/api/NutchServer.java
@@ -44,7 +44,7 @@ import org.apache.nutch.api.resources.DbResource;
 import org.apache.nutch.api.resources.JobResource;
 import org.apache.nutch.api.resources.SeedResource;
 import org.apache.nutch.api.security.AuthenticationTypeEnum;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 import org.restlet.Component;
 import org.restlet.Context;
 import org.restlet.Server;
@@ -168,7 +168,7 @@ public class NutchServer extends Application {
       parameters.add("sslContextFactory", 
"org.restlet.engine.ssl.DefaultSslContextFactory");
 
       String keyStorePath = configManager.get(activeConfId)
-              .get("restapi.auth.ssl.storepath", "etc/nutch-ssl.keystore.jks");
+              .get("restapi.auth.ssl.storepath", "nutch-ssl.keystore.jks");
       parameters.add("keyStorePath", keyStorePath);
 
       String keyStorePassword = configManager.get(activeConfId)
@@ -191,7 +191,7 @@ public class NutchServer extends Application {
     application.add(this);
     application.setStatusService(new ErrorStatusService());
     childContext.getAttributes().put(NUTCH_SERVER, this);
-    application.setRoles(SecurityUtil.getRoles(application));
+    application.setRoles(SecurityUtils.getRoles(application));
 
     switch (authenticationType) {
       case NONE:
@@ -201,7 +201,7 @@ public class NutchServer extends Application {
       case BASIC:
         ChallengeAuthenticator challengeGuard = new 
ChallengeAuthenticator(null, ChallengeScheme.HTTP_BASIC, "Nutch REST API 
Realm");
         //Create in-memory users with roles
-        MemoryRealm basicAuthRealm = SecurityUtil.constructRealm(application, 
configManager, confId);
+        MemoryRealm basicAuthRealm = SecurityUtils.constructRealm(application, 
configManager, confId);
         //Attach verifier to check authentication and enroler to determine 
roles
         challengeGuard.setVerifier(basicAuthRealm.getVerifier());
         challengeGuard.setEnroler(basicAuthRealm.getEnroler());
@@ -212,7 +212,7 @@ public class NutchServer extends Application {
       case DIGEST:
         DigestAuthenticator digestGuard = new DigestAuthenticator(null, "Nutch 
REST API Realm", "NutchSecretKey");
         //Create in-memory users with roles
-        MemoryRealm digestAuthRealm = SecurityUtil.constructRealm(application, 
configManager, confId);
+        MemoryRealm digestAuthRealm = 
SecurityUtils.constructRealm(application, configManager, confId);
         digestGuard.setWrappedVerifier((LocalVerifier) 
digestAuthRealm.getVerifier());
         digestGuard.setEnroler(digestAuthRealm.getEnroler());
         digestGuard.setNext(application);

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/resources/AdminResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/resources/AdminResource.java 
b/src/java/org/apache/nutch/api/resources/AdminResource.java
index cfbf8d5..5cc0b55 100644
--- a/src/java/org/apache/nutch/api/resources/AdminResource.java
+++ b/src/java/org/apache/nutch/api/resources/AdminResource.java
@@ -32,7 +32,7 @@ import javax.ws.rs.core.SecurityContext;
 
 import org.apache.nutch.api.model.response.NutchStatus;
 import org.apache.nutch.api.model.response.JobInfo.State;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,7 +50,7 @@ public class AdminResource extends AbstractResource {
   @GET
   @Path("/")
   public NutchStatus getNutchStatus(@Context HttpHeaders headers) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     NutchStatus status = new NutchStatus();
     status.setStartDate(new Date(server.getStarted()));
     status.setConfiguration(configManager.list());
@@ -65,7 +65,7 @@ public class AdminResource extends AbstractResource {
   @Path("/stop")
   @Produces(MediaType.TEXT_PLAIN)
   public String stop(@QueryParam("force") boolean force) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (!server.canStop(force)) {
       LOG.info("Command 'stop' denied due to unfinished jobs");
       return "Can't stop now. There are jobs running. Try force option.";
@@ -76,7 +76,7 @@ public class AdminResource extends AbstractResource {
   }
 
   private void scheduleServerStop() {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     LOG.info("Server shutdown scheduled in {} seconds", DELAY_SEC);
     Thread thread = new Thread() {
       public void run() {

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/resources/ConfigResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/resources/ConfigResource.java 
b/src/java/org/apache/nutch/api/resources/ConfigResource.java
index bc65826..ea8e577 100644
--- a/src/java/org/apache/nutch/api/resources/ConfigResource.java
+++ b/src/java/org/apache/nutch/api/resources/ConfigResource.java
@@ -36,7 +36,7 @@ import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.SecurityContext;
 
 import org.apache.nutch.api.model.request.NutchConfig;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 
 @Path("/config")
 public class ConfigResource extends AbstractResource {
@@ -68,7 +68,7 @@ public class ConfigResource extends AbstractResource {
   @DELETE
   @Path("/{configId}")
   public void deleteConfig(@PathParam("configId") String configId) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     configManager.delete(configId);
   }
 
@@ -77,7 +77,7 @@ public class ConfigResource extends AbstractResource {
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.TEXT_PLAIN)
   public String createConfig(NutchConfig newConfig) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (newConfig == null) {
       throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
           .entity("Nutch configuration cannot be empty!").build());
@@ -89,7 +89,7 @@ public class ConfigResource extends AbstractResource {
   @Path("/{config}/{property}")
   public Response update(@PathParam("config") String config,
       @PathParam("property") String property, @FormParam("value") String 
value) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (value == null) {
       throwBadRequestException("Missing property value!");
     }

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/resources/DbResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/resources/DbResource.java 
b/src/java/org/apache/nutch/api/resources/DbResource.java
index b137dea..7b8ef46 100644
--- a/src/java/org/apache/nutch/api/resources/DbResource.java
+++ b/src/java/org/apache/nutch/api/resources/DbResource.java
@@ -30,7 +30,7 @@ import javax.ws.rs.core.SecurityContext;
 import org.apache.nutch.api.impl.db.DbReader;
 import org.apache.nutch.api.model.request.DbFilter;
 import org.apache.nutch.api.model.response.DbQueryResult;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 
 @Path("/db")
 public class DbResource extends AbstractResource {
@@ -43,7 +43,7 @@ public class DbResource extends AbstractResource {
   @POST
   @Consumes(MediaType.APPLICATION_JSON)
   public DbQueryResult runQuery(DbFilter filter) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (filter == null) {
       throwBadRequestException("Filter cannot be null!");
     }

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/resources/JobResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/resources/JobResource.java 
b/src/java/org/apache/nutch/api/resources/JobResource.java
index 2ada981..0f1a540 100644
--- a/src/java/org/apache/nutch/api/resources/JobResource.java
+++ b/src/java/org/apache/nutch/api/resources/JobResource.java
@@ -32,7 +32,7 @@ import javax.ws.rs.core.SecurityContext;
 import org.apache.nutch.api.model.request.JobConfig;
 import org.apache.nutch.api.model.response.JobInfo;
 import org.apache.nutch.api.model.response.JobInfo.State;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 
 @Path(value = "/job")
 public class JobResource extends AbstractResource {
@@ -72,7 +72,7 @@ public class JobResource extends AbstractResource {
   @Consumes(MediaType.APPLICATION_JSON)
   @Produces(MediaType.TEXT_PLAIN)
   public String create(JobConfig config) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (config == null) {
       throwBadRequestException("Job configuration is required!");
     }

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/resources/SeedResource.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/resources/SeedResource.java 
b/src/java/org/apache/nutch/api/resources/SeedResource.java
index d7439e0..7ea1b8d 100644
--- a/src/java/org/apache/nutch/api/resources/SeedResource.java
+++ b/src/java/org/apache/nutch/api/resources/SeedResource.java
@@ -38,7 +38,7 @@ import javax.ws.rs.core.SecurityContext;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.nutch.api.model.request.SeedList;
 import org.apache.nutch.api.model.request.SeedUrl;
-import org.apache.nutch.api.security.SecurityUtil;
+import org.apache.nutch.api.security.SecurityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,7 +60,7 @@ public class SeedResource extends AbstractResource {
    * @return
    */
   public String createSeedFile(SeedList seedList) {
-    SecurityUtil.allowOnlyAdmin(securityContext);
+    SecurityUtils.allowOnlyAdmin(securityContext);
     if (seedList == null) {
       throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
           .entity("Seed list cannot be empty!").build());

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/security/SecurityUtil.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/security/SecurityUtil.java 
b/src/java/org/apache/nutch/api/security/SecurityUtil.java
deleted file mode 100644
index 734207a..0000000
--- a/src/java/org/apache/nutch/api/security/SecurityUtil.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * 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.nutch.api.security;
-
-import org.apache.nutch.api.ConfManager;
-import org.apache.nutch.api.resources.ConfigResource;
-import org.restlet.ext.jaxrs.JaxRsApplication;
-import org.restlet.security.MapVerifier;
-import org.restlet.security.MemoryRealm;
-import org.restlet.security.Role;
-import org.restlet.security.User;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.SecurityContext;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Utility class for security operations for NutchServer REST API.
- *
- */
-public final class SecurityUtil {
-
-  private static final Logger LOG = 
LoggerFactory.getLogger(SecurityUtil.class);
-
-  /**
-   * Private constructor to prevent instantiation
-   */
-  private SecurityUtil() {
-  }
-
-  /**
-   * Returns roles defined at {@link 
org.apache.nutch.api.security.AuthorizationRoleEnum} associated with
-   * {@link org.restlet.ext.jaxrs.JaxRsApplication} type application
-   *
-   * @param application {@link org.restlet.ext.jaxrs.JaxRsApplication} type 
application
-   * @return roles associated with given {@link 
org.restlet.ext.jaxrs.JaxRsApplication} type application
-   */
-  public static List<Role> getRoles(JaxRsApplication application) {
-    List<Role> roles = new ArrayList<>();
-    for (AuthorizationRoleEnum authorizationRole : 
AuthorizationRoleEnum.values()) {
-      roles.add(new Role(application, authorizationRole.toString()));
-    }
-    return roles;
-  }
-
-  /**
-   * Constructs realm
-   *
-   * @param application {@link org.restlet.ext.jaxrs.JaxRsApplication 
}application
-   * @param configManager {@link org.apache.nutch.api.ConfManager} type config 
manager
-   * @param confId Configuration id to use from {@link 
org.apache.nutch.api.ConfManager} type config manager
-   * @return realm
-   */
-  public static MemoryRealm constructRealm(JaxRsApplication application, 
ConfManager configManager, String confId){
-    MemoryRealm realm = new MemoryRealm();
-    MapVerifier mapVerifier = new MapVerifier();
-    String[] users = 
configManager.get(confId).getTrimmedStrings("restapi.auth.users", 
"admin|admin|admin,user|user|user");
-    if (users.length <= 1) {
-      throw new IllegalStateException("Check users definition of 
restapi.auth.users at nutch-site.xml ");
-    }
-    for (String userconf : users) {
-      String[] userDetail = userconf.split("\\|");
-      if(userDetail.length != 3) {
-        LOG.error("Check user definition of restapi.auth.users at 
nutch-site.xml");
-        throw new IllegalStateException("Check user definition of 
restapi.auth.users at nutch-site.xml ");
-      }
-      User user = new User(userDetail[0], userDetail[1]);
-      mapVerifier.getLocalSecrets().put(user.getIdentifier(), 
user.getSecret());
-      realm.getUsers().add(user);
-      realm.map(user, Role.get(application, userDetail[2]));
-      LOG.info("User added: {}", userDetail[0]);
-    }
-      realm.setVerifier(mapVerifier);
-      return realm;
-  }
-
-  /**
-   * Check for allowing only admin role
-   *
-   * @param securityContext to check role of logged-in user
-   */
-  public static void allowOnlyAdmin(SecurityContext securityContext) {
-    if (securityContext.getAuthenticationScheme() != null
-        && 
!securityContext.isUserInRole(AuthorizationRoleEnum.ADMIN.toString())) {
-      throw new 
WebApplicationException(Response.status(Response.Status.FORBIDDEN)
-          .entity("User does not have required " + AuthorizationRoleEnum.ADMIN 
+ " role!").build());
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/java/org/apache/nutch/api/security/SecurityUtils.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/nutch/api/security/SecurityUtils.java 
b/src/java/org/apache/nutch/api/security/SecurityUtils.java
new file mode 100644
index 0000000..8fd56f9
--- /dev/null
+++ b/src/java/org/apache/nutch/api/security/SecurityUtils.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * 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.nutch.api.security;
+
+import org.apache.nutch.api.ConfManager;
+import org.restlet.ext.jaxrs.JaxRsApplication;
+import org.restlet.security.MapVerifier;
+import org.restlet.security.MemoryRealm;
+import org.restlet.security.Role;
+import org.restlet.security.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for security operations for NutchServer REST API.
+ *
+ */
+public final class SecurityUtils {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(SecurityUtils.class);
+
+  /**
+   * Private constructor to prevent instantiation
+   */
+  private SecurityUtils() {
+  }
+
+  /**
+   * Returns roles defined at {@link 
org.apache.nutch.api.security.AuthorizationRoleEnum} associated with
+   * {@link org.restlet.ext.jaxrs.JaxRsApplication} type application
+   *
+   * @param application {@link org.restlet.ext.jaxrs.JaxRsApplication} type 
application
+   * @return roles associated with given {@link 
org.restlet.ext.jaxrs.JaxRsApplication} type application
+   */
+  public static List<Role> getRoles(JaxRsApplication application) {
+    List<Role> roles = new ArrayList<>();
+    for (AuthorizationRoleEnum authorizationRole : 
AuthorizationRoleEnum.values()) {
+      roles.add(new Role(application, authorizationRole.toString()));
+    }
+    return roles;
+  }
+
+  /**
+   * Constructs realm
+   *
+   * @param application {@link org.restlet.ext.jaxrs.JaxRsApplication 
}application
+   * @param configManager {@link org.apache.nutch.api.ConfManager} type config 
manager
+   * @param confId Configuration id to use from {@link 
org.apache.nutch.api.ConfManager} type config manager
+   * @return realm
+   */
+  public static MemoryRealm constructRealm(JaxRsApplication application, 
ConfManager configManager, String confId){
+    MemoryRealm realm = new MemoryRealm();
+    MapVerifier mapVerifier = new MapVerifier();
+    String[] users = 
configManager.get(confId).getTrimmedStrings("restapi.auth.users", 
"admin|admin|admin,user|user|user");
+    if (users.length < 1) {
+      throw new IllegalStateException("Check users definition of 
restapi.auth.users at nutch-site.xml ");
+    }
+    for (String userconf : users) {
+      String[] userDetail = userconf.split("\\|");
+      if(userDetail.length != 3) {
+        LOG.error("Check user definition of restapi.auth.users at 
nutch-site.xml");
+        throw new IllegalStateException("Check user definition of 
restapi.auth.users at nutch-site.xml ");
+      }
+      User user = new User(userDetail[0], userDetail[1]);
+      mapVerifier.getLocalSecrets().put(user.getIdentifier(), 
user.getSecret());
+      realm.getUsers().add(user);
+      realm.map(user, Role.get(application, userDetail[2]));
+      LOG.info("User added: {}", userDetail[0]);
+    }
+      realm.setVerifier(mapVerifier);
+      return realm;
+  }
+
+  /**
+   * Check for allowing only admin role
+   *
+   * @param securityContext to check role of logged-in user
+   */
+  public static void allowOnlyAdmin(SecurityContext securityContext) {
+    if (securityContext.getAuthenticationScheme() != null
+        && 
!securityContext.isUserInRole(AuthorizationRoleEnum.ADMIN.toString())) {
+      throw new 
WebApplicationException(Response.status(Response.Status.FORBIDDEN)
+          .entity("User does not have required " + AuthorizationRoleEnum.ADMIN 
+ " role!").build());
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/nutch-site.xml
----------------------------------------------------------------------
diff --git a/src/test/nutch-site.xml b/src/test/nutch-site.xml
index 4dbce0c..bdeb562 100644
--- a/src/test/nutch-site.xml
+++ b/src/test/nutch-site.xml
@@ -55,7 +55,7 @@
   <value>nutch-ssl.keystore.jks</value>
   <description>
     Key store path for jks file. restapi.auth property should be set to SSL to 
use this property.
-    etc/nutch-ssl.keystore.jks is used for restapi.auth.ssl.storepath as 
default.
+    nutch-ssl.keystore.jks is used for restapi.auth.ssl.storepath as default.
   </description>
 </property>
 

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/nutch-ssl.keystore.jks
----------------------------------------------------------------------
diff --git a/src/test/nutch-ssl.keystore.jks b/src/test/nutch-ssl.keystore.jks
index 9d0bd01..4fc4514 100644
Binary files a/src/test/nutch-ssl.keystore.jks and 
b/src/test/nutch-ssl.keystore.jks differ

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/nutch.cer
----------------------------------------------------------------------
diff --git a/src/test/nutch.cer b/src/test/nutch.cer
new file mode 100644
index 0000000..a3317b1
Binary files /dev/null and b/src/test/nutch.cer differ

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/org/apache/nutch/api/AbstractNutchAPITestBase.java
----------------------------------------------------------------------
diff --git a/src/test/org/apache/nutch/api/AbstractNutchAPITestBase.java 
b/src/test/org/apache/nutch/api/AbstractNutchAPITestBase.java
index 3cdff23..2e4e61c 100644
--- a/src/test/org/apache/nutch/api/AbstractNutchAPITestBase.java
+++ b/src/test/org/apache/nutch/api/AbstractNutchAPITestBase.java
@@ -27,7 +27,24 @@ import org.restlet.data.ChallengeScheme;
 import org.restlet.resource.ClientResource;
 import org.restlet.resource.ResourceException;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 /**
  * Base class for Nutc REST API tests.
@@ -154,33 +171,89 @@ public abstract class AbstractNutchAPITestBase {
     return digestChallengeRequest;
   }
 
-  private void initializeSSLProperties() {
-    conf.set("restapi.auth.ssl.storepath", "src/test/nutch-ssl.keystore.jks");
+  private void initializeSSLProperties() throws FileNotFoundException {
+    conf.set("restapi.auth.ssl.storepath", 
getResourcePath("nutch-ssl.keystore.jks"));
     conf.set("restapi.auth.ssl.storepass", "password");
     conf.set("restapi.auth.ssl.keypass", "password");
   }
 
+  private void loadCertificate() throws CertificateException, 
NoSuchAlgorithmException, KeyStoreException, IOException {
+    String testTrustKeyStorePath = getResourcePath("testTrustKeyStore");
+    File file = new File(testTrustKeyStorePath);
+    InputStream localCertIn = new FileInputStream(file);
+
+    char[] password = "testpassword".toCharArray();
+    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+    ks.load(localCertIn, password);
+
+    localCertIn.close();
+
+    if (ks.containsAlias("nutch")) {
+      return;
+    }
+
+    String cerFilePath = getResourcePath("nutch.cer");
+
+    InputStream certIn = new FileInputStream(cerFilePath);
+    BufferedInputStream bis = new BufferedInputStream(certIn);
+    CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+    while (bis.available() > 0) {
+      Certificate cert = cf.generateCertificate(bis);
+      ks.setCertificateEntry("nutch", cert);
+    }
+
+    certIn.close();
+    OutputStream out = new FileOutputStream(file);
+    ks.store(out, password);
+    out.close();
+  }
+
   /**
-   * Starts the server with given authentication type
+   * Starts the server with given authentication type.
+   * Use {@link #startSSLServer()} for a {@link AuthenticationTypeEnum#SSL} 
authentication type server.
    *
    * @param authenticationType authentication type
    */
   public void startServer(AuthenticationTypeEnum authenticationType) {
     conf.set("restapi.auth", authenticationType.toString());
-    if(AuthenticationTypeEnum.SSL.equals(authenticationType)) {
-      initializeSSLProperties();
-    }
-
     RAMConfManager ramConfManager = new 
RAMConfManager(NutchConfiguration.getUUID(conf), conf);
     nutchServer = new NutchServer(ramConfManager, 
NutchConfiguration.getUUID(conf));
     nutchServer.start();
   }
 
   /**
-   * Stops server
+   * Starts the SSL server
+   *
+   */
+  public void startSSLServer() throws IOException, CertificateException, 
NoSuchAlgorithmException, KeyStoreException {
+    conf.set("restapi.auth", AuthenticationTypeEnum.SSL.toString());
+    initializeSSLProperties();
+    loadCertificate();
+    startServer(AuthenticationTypeEnum.SSL);
+  }
+
+  /**
+   * Stops the server
    */
   public void stopServer() {
     nutchServer.stop(true);
   }
 
+  protected String getResourcePath(String fileName) throws 
FileNotFoundException {
+    URL resourceFilePath = 
this.getClass().getClassLoader().getResource(fileName);
+    if (resourceFilePath == null) {
+      throw new FileNotFoundException("Resource could not found: " + fileName);
+    }
+    return resourceFilePath.getPath();
+  }
+
+  protected void rollbackSystemProperty(String key, String initialValue){
+    if (initialValue != null) {
+      System.setProperty(key, initialValue);
+    } else {
+      System.clearProperty(key);
+    }
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/org/apache/nutch/api/TestNutchAPI.java
----------------------------------------------------------------------
diff --git a/src/test/org/apache/nutch/api/TestNutchAPI.java 
b/src/test/org/apache/nutch/api/TestNutchAPI.java
index 56aed92..a4a8fb8 100644
--- a/src/test/org/apache/nutch/api/TestNutchAPI.java
+++ b/src/test/org/apache/nutch/api/TestNutchAPI.java
@@ -18,10 +18,14 @@ package org.apache.nutch.api;
 
 import org.apache.nutch.api.security.AuthenticationTypeEnum;
 import org.junit.After;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.restlet.data.ChallengeScheme;
 
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
 /**
  * Test class for {@link org.apache.nutch.api.NutchServer}
  */
@@ -71,21 +75,26 @@ public class TestNutchAPI extends AbstractNutchAPITestBase {
   }
 
   /**
-   * Test SSL for invalid username/password pair,
-   * authorized username/password pair and insufficient privileged 
username/password pair
+   * Test SSL connection
    */
-  @Ignore
   @Test
-  public void testSSL() {
-    startServer(AuthenticationTypeEnum.SSL);
-    //Check for an invalid username/password pair
-    testRequest(401, 8081, "xxx", "xxx");
+  public void testSSL() throws IOException, CertificateException, 
NoSuchAlgorithmException, KeyStoreException {
+    startSSLServer();
 
-    //Check for an authorized username/password pair
-    testRequest(200, 8081, "admin", "admin");
+    String defaultTrustStore = System.getProperty("javax.net.ssl.trustStore");
+    String defaultTrustStoreType = 
System.getProperty("javax.net.ssl.trustStoreType");
+    String defaultTrustStorePassword = 
System.getProperty("javax.net.ssl.trustStorePassword");
+
+    System.setProperty("javax.net.ssl.trustStore" , 
getResourcePath("testTrustKeyStore"));
+    System.setProperty("javax.net.ssl.trustStoreType", "JKS");
+    System.setProperty("javax.net.ssl.trustStorePassword", "testpassword");
+
+    testRequest(200, 8081);
+
+    rollbackSystemProperty("javax.net.ssl.trustStore", defaultTrustStore);
+    rollbackSystemProperty("javax.net.ssl.trustStoreType", 
defaultTrustStoreType);
+    rollbackSystemProperty("javax.net.ssl.trustStorePassword", 
defaultTrustStorePassword);
 
-    //Check for an insufficient privileged username/password pair
-    testRequest(403, 8081, "user", "user");
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/nutch/blob/75d846cf/src/test/testTrustKeyStore
----------------------------------------------------------------------
diff --git a/src/test/testTrustKeyStore b/src/test/testTrustKeyStore
new file mode 100644
index 0000000..5fdd2fd
Binary files /dev/null and b/src/test/testTrustKeyStore differ

Reply via email to