eagle-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From h..@apache.org
Subject [2/3] eagle git commit: [EAGLE-918] Support auth annotations PermitAll/DenyAll/RolesAllowed and API
Date Wed, 22 Feb 2017 08:12:38 GMT
http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthBuilder.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthBuilder.java b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthBuilder.java
new file mode 100644
index 0000000..8d41a90
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthBuilder.java
@@ -0,0 +1,99 @@
+/*
+ * 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.eagle.server.security;
+
+import com.google.common.cache.CacheBuilderSpec;
+import com.sun.jersey.api.core.HttpContext;
+import com.sun.jersey.api.model.Parameter;
+import com.sun.jersey.core.spi.component.ComponentContext;
+import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable;
+import com.sun.jersey.spi.inject.Injectable;
+import io.dropwizard.auth.Auth;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.CachingAuthenticator;
+import io.dropwizard.auth.basic.BasicAuthProvider;
+import io.dropwizard.auth.basic.BasicCredentials;
+import io.dropwizard.setup.Environment;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.server.security.authenticator.LdapBasicAuthenticator;
+import org.apache.eagle.server.security.authenticator.SimpleBasicAuthenticator;
+import org.apache.eagle.server.security.config.AuthenticationConfig;
+
+import java.util.Arrays;
+
+public class BasicAuthBuilder {
+    private static final String SIMPLE_MODE_REALM = "SIMPLE_BASIC_AUTHENTICATION";
+    private static final String LDAP_MODE_REALM = "LDAP_BASIC_AUTHENTICATION";
+    private final Authenticator<BasicCredentials, User> authenticator;
+    private final BasicAuthProvider basicAuthProvider;
+    private AuthenticationConfig authConfig;
+    private Environment environment;
+
+    public BasicAuthBuilder(AuthenticationConfig authConfig, Environment environment) {
+        this.authConfig = authConfig;
+        this.environment = environment;
+        boolean needsCaching = authConfig.needsCaching();
+        Authenticator<BasicCredentials, User> authenticator;
+        String realm;
+        if (authConfig.isEnabled()) {
+            switch (authConfig.getMode()) {
+                case "simple":
+                    authenticator = new SimpleBasicAuthenticator(authConfig.getSimple());
+                    realm = SIMPLE_MODE_REALM;
+                    break;
+                case "ldap":
+                    authenticator = new LdapBasicAuthenticator(authConfig.getLdap());
+                    realm = LDAP_MODE_REALM;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid auth mode " + authConfig.getMode());
+            }
+            if (needsCaching) {
+                authenticator = cache(authenticator);
+            }
+            this.authenticator = authenticator;
+            this.basicAuthProvider = new BasicAuthProvider<>(this.authenticator, realm);
+        } else {
+            this.authenticator = null;
+            this.basicAuthProvider = new BasicAuthProvider<User>(null, "") {
+                public Injectable<User> getInjectable(ComponentContext ic, Auth a, Parameter c) {
+                    return new AbstractHttpContextInjectable<User>() {
+                        public User getValue(HttpContext c) {
+                            User user =  new User();
+                            user.setName("anonymous");
+                            user.setFirstName("Anonymous User (auth: false)");
+                            user.setRoles(Arrays.asList(User.Role.ALL_ROLES));
+                            return user;
+                        }
+                    };
+                }
+            };
+        }
+    }
+
+    public BasicAuthProvider getBasicAuthProvider() {
+        return this.basicAuthProvider;
+    }
+
+    public Authenticator<BasicCredentials, User> getBasicAuthenticator() {
+        return this.authenticator;
+    }
+
+    private Authenticator<BasicCredentials, User> cache(Authenticator<BasicCredentials, User> authenticator) {
+        return new CachingAuthenticator<>(environment.metrics(), authenticator, CacheBuilderSpec.parse(authConfig.getCachePolicy()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthRequestFilter.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthRequestFilter.java b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthRequestFilter.java
new file mode 100644
index 0000000..1542505
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthRequestFilter.java
@@ -0,0 +1,161 @@
+package org.apache.eagle.server.security;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.sun.jersey.api.model.AbstractMethod;
+import com.sun.jersey.core.util.Base64;
+import com.sun.jersey.core.util.Priority;
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerRequestFilter;
+import io.dropwizard.auth.Auth;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
+import org.apache.eagle.common.rest.RESTResponse;
+import org.apache.eagle.common.security.DenyAll;
+import org.apache.eagle.common.security.PermitAll;
+import org.apache.eagle.common.security.RolesAllowed;
+import org.apache.eagle.common.security.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Priorities;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.Provider;
+import java.lang.reflect.Parameter;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+@Provider
+@Priority(Priorities.AUTHORIZATION)
+public class BasicAuthRequestFilter implements ContainerRequestFilter {
+    private final Authenticator<BasicCredentials, User> authenticator;
+    private final AbstractMethod method;
+    private static final Logger LOG = LoggerFactory.getLogger(BasicAuthRequestFilter.class);
+    private boolean isSecurityDefined = false;
+    private boolean isAuthRequired = false;
+    private boolean hasPermitAllAnnotation = false;
+    private boolean hasDenyAllAnnotation = false;
+    private boolean hasRolesAllowedAnnotation = false;
+
+    public BasicAuthRequestFilter(Authenticator<BasicCredentials, User> authenticator, AbstractMethod method) {
+        this.authenticator = authenticator;
+        this.method = method;
+        this.hasPermitAllAnnotation = method.isAnnotationPresent(PermitAll.class);
+        this.hasDenyAllAnnotation = method.isAnnotationPresent(DenyAll.class);
+        this.hasRolesAllowedAnnotation = method.isAnnotationPresent(RolesAllowed.class);
+        this.isSecurityDefined = this.hasPermitAllAnnotation || this.hasDenyAllAnnotation || this.hasRolesAllowedAnnotation;
+        for (Parameter parameter : method.getMethod().getParameters()) {
+            if (isSecurityDefined && isAuthRequired) {
+                break;
+            }
+            Auth[] authAnnotations = parameter.getAnnotationsByType(Auth.class);
+            this.isSecurityDefined = this.isSecurityDefined || authAnnotations.length > 0;
+            for (Auth auth : authAnnotations) {
+                this.isAuthRequired = this.isAuthRequired || auth.required();
+            }
+        }
+        Preconditions.checkArgument(!(this.hasDenyAllAnnotation && this.hasPermitAllAnnotation), "Conflict @DenyAll and @PermitAll on method " + this.method.toString());
+    }
+
+
+    private static final String AUTHORIZATION_PROPERTY = "Authorization";
+    private static final String AUTHENTICATION_SCHEME = "Basic";
+    private static final Response UNAUTHORIZED_ACCESS_DENIED = RESTResponse.builder()
+        .message("Unauthorized access denied")
+        .status(false, Response.Status.UNAUTHORIZED)
+        .build();
+
+    private static final Response ALL_ACCESS_DENIED = RESTResponse.builder()
+        .message("Access denied")
+        .status(false, Response.Status.FORBIDDEN)
+        .build();
+
+    @Override
+    public ContainerRequest filter(ContainerRequest containerRequest) {
+        if (!isSecurityDefined) {
+            return containerRequest;
+        }
+        //Access denied for all
+
+        if (hasDenyAllAnnotation) {
+            throw new WebApplicationException(ALL_ACCESS_DENIED);
+        }
+
+        //Get request headers
+        final MultivaluedMap<String, String> headers = containerRequest.getRequestHeaders();
+
+        //Fetch authorization header
+        final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
+
+        //If no authorization information present; block access
+        if ((authorization == null || authorization.isEmpty()) && isAuthRequired) {
+            throw new WebApplicationException(UNAUTHORIZED_ACCESS_DENIED);
+        }
+
+        if (authorization != null) {
+            //Get encoded username and password
+            final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");
+
+            //Decode username and password
+            String usernameAndPassword = new String(Base64.decode(encodedUserPassword.getBytes()));
+
+            //Split username and password tokens
+            final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
+            final String username = tokenizer.nextToken();
+            final String password = tokenizer.nextToken();
+
+            try {
+                Optional<User> userOptional = this.authenticator.authenticate(new BasicCredentials(username, password));
+                if (userOptional.isPresent()) {
+                    User user = userOptional.get();
+                    containerRequest.setSecurityContext(new SecurityContext() {
+                        @Override
+                        public Principal getUserPrincipal() {
+                            return user;
+                        }
+
+                        @Override
+                        public boolean isUserInRole(String role) {
+                            return user.isInRole(User.Role.locateCaseInsensitive(role));
+                        }
+
+                        @Override
+                        public boolean isSecure() {
+                            return "https".equals(containerRequest.getRequestUri().getScheme());
+                        }
+
+                        @Override
+                        public String getAuthenticationScheme() {
+                            return "Basic Auth";
+                        }
+                    });
+
+                    //Verify user access
+                    if (hasRolesAllowedAnnotation && !hasPermitAllAnnotation) {
+                        RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
+                        if (!user.isInRole(rolesAnnotation.value())) {
+                            throw new WebApplicationException(
+                                RESTResponse.builder()
+                                    .status(false, Response.Status.FORBIDDEN)
+                                    .message("Access forbidden, required roles: " + Arrays.toString(rolesAnnotation.value()))
+                                    .build());
+                        }
+                    }
+                } else {
+                    throw new WebApplicationException(UNAUTHORIZED_ACCESS_DENIED);
+                }
+            } catch (AuthenticationException e) {
+                LOG.error("Server authentication error: " + e.getMessage(), e);
+                throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
+                    .entity("Server authentication error: " + e.getMessage()).build());
+            }
+        }
+        return containerRequest;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthResourceFilterFactory.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthResourceFilterFactory.java b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthResourceFilterFactory.java
new file mode 100644
index 0000000..e6b8522
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/BasicAuthResourceFilterFactory.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.security;
+
+
+import com.sun.jersey.api.model.AbstractMethod;
+import com.sun.jersey.spi.container.ContainerRequestFilter;
+import com.sun.jersey.spi.container.ContainerResponseFilter;
+import com.sun.jersey.spi.container.ResourceFilter;
+import com.sun.jersey.spi.container.ResourceFilterFactory;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
+import org.apache.eagle.common.security.User;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class BasicAuthResourceFilterFactory implements ResourceFilterFactory {
+    private final Authenticator<BasicCredentials, User> authenticator;
+
+    public BasicAuthResourceFilterFactory(Authenticator<BasicCredentials, User> authenticator) {
+        this.authenticator = authenticator;
+    }
+
+    @Override
+    public List<ResourceFilter> create(AbstractMethod abstractMethod) {
+        return Arrays.asList(new ResourceFilter() {
+            @Override
+            public ContainerRequestFilter getRequestFilter() {
+                return new BasicAuthRequestFilter(authenticator, abstractMethod);
+            }
+
+            @Override
+            public ContainerResponseFilter getResponseFilter() {
+                return null;
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticator.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticator.java b/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticator.java
new file mode 100644
index 0000000..bc50c82
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticator.java
@@ -0,0 +1,106 @@
+/*
+ * 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.eagle.server.security.authenticator;
+
+import com.google.common.base.Optional;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.server.security.config.LdapConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.naming.Context;
+import javax.naming.directory.InitialDirContext;
+import java.io.File;
+import java.util.Hashtable;
+
+public class LdapBasicAuthenticator implements Authenticator<BasicCredentials, User> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(LdapBasicAuthenticator.class);
+    private static final String LDAP_LDAP_CTX_FACTORY_NAME = "com.sun.jndi.ldap.LdapCtxFactory";
+    private static final String LDAP_CONNECT_TIMEOUT_KEY = "com.sun.jndi.ldap.connect.timeout";
+    private static final String LDAP_READ_TIMEOUT_KEY = "com.sun.jndi.ldap.read.timeout";
+    private static final String SYS_PROP_SSL_KEY_STORE = "javax.net.ssl.keyStore";
+    private static final String SYS_PROP_SSL_TRUST_STORE = "javax.net.ssl.trustStore";
+    private static final String LDAPS_URL_PREFIX = "ldaps://";
+    private static final String SSL_PROTOCOL_VALUE = "ssl";
+    private LdapConfig settings = null;
+
+    public LdapBasicAuthenticator(LdapConfig settings) {
+        this.settings = settings;
+    }
+
+    public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
+        String sanitizedUsername = sanitizeUsername(credentials.getUsername());
+        try {
+            new InitialDirContext(getContextEnvironment(sanitizedUsername, credentials.getPassword()));
+            return Optional.of(new User(sanitizedUsername));
+        } catch (javax.naming.AuthenticationException ae) {
+            LOGGER.warn(String.format("Authentication failed for user[%s]: wrong username or password", sanitizedUsername));
+            return Optional.absent();
+        } catch (Exception e) {
+            throw new AuthenticationException(String.format("Error occurs while trying to authenticate for user[%s]: %s", sanitizedUsername, e.getMessage()), e);
+        }
+    }
+
+    Hashtable<String, String> getContextEnvironment(String sanitizedUsername, String password) {
+        String providerUrl = settings.getProviderUrl();
+        if (providerUrl == null) {
+            throw new IllegalArgumentException("providerUrl of the ldap service shouldn't be null");
+        }
+
+        Hashtable<String, String> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_LDAP_CTX_FACTORY_NAME);
+        env.put(Context.PROVIDER_URL, providerUrl);
+        env.put(LDAP_CONNECT_TIMEOUT_KEY, String.valueOf(settings.getConnectingTimeout().toMilliseconds()));
+        env.put(LDAP_READ_TIMEOUT_KEY, String.valueOf(settings.getReadingTimeout().toMilliseconds()));
+
+        String strategy = settings.getStrategy();
+        if (!"".equals(strategy)) {
+            env.put(Context.SECURITY_AUTHENTICATION, strategy);
+        }
+
+        if (providerUrl.toLowerCase().startsWith(LDAPS_URL_PREFIX)) { // using ldap over ssl to authenticate
+            env.put(Context.SECURITY_PROTOCOL, SSL_PROTOCOL_VALUE);
+
+            String certificateAbsolutePath = settings.getCertificateAbsolutePath();
+            if (certificateAbsolutePath == null || "".equals(certificateAbsolutePath)) {
+                throw new RuntimeException("The attribute 'certificateAbsolutePath' must be set when using ldap over ssl to authenticate.");
+            }
+            if (!new File(certificateAbsolutePath).exists()) {
+                throw new RuntimeException(String.format("The file specified not existing: %s", certificateAbsolutePath));
+            }
+
+            System.setProperty(SYS_PROP_SSL_KEY_STORE, certificateAbsolutePath);
+            System.setProperty(SYS_PROP_SSL_TRUST_STORE, certificateAbsolutePath);
+        }
+
+        env.put(Context.SECURITY_PRINCIPAL, comprisePrincipal(sanitizedUsername));
+        env.put(Context.SECURITY_CREDENTIALS, password);
+        return env;
+    }
+
+    String comprisePrincipal(String sanitizedUsername) {
+        return settings.getPrincipalTemplate().replaceAll("\\$\\{USERNAME\\}", sanitizedUsername);
+    }
+
+    String sanitizeUsername(String username) {
+        return username.replaceAll("[^a-zA-Z0-9_.]", "");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticator.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticator.java b/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticator.java
new file mode 100644
index 0000000..63dfd3b
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.eagle.server.security.authenticator;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.basic.BasicCredentials;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.server.security.config.SimpleConfig;
+import org.apache.eagle.server.security.config.UserAccount;
+import org.apache.eagle.server.security.encrypt.EncryptorFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+public class SimpleBasicAuthenticator implements Authenticator<BasicCredentials, User> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleBasicAuthenticator.class);
+    private final Map<String, UserAccount> userAccountRepository;
+
+    public SimpleBasicAuthenticator(SimpleConfig config) {
+        userAccountRepository = new HashMap<>();
+        for (UserAccount userAccount : config.getAccounts()) {
+            Preconditions.checkNotNull(userAccount.getName(), " Username is null " + userAccount);
+            Preconditions.checkArgument(!userAccountRepository.containsKey(userAccount.getName()), "Duplicated user name: " + userAccount.getName());
+            if (userAccount.getRoles() == null) {
+                LOGGER.warn("UserPrincipal {} has no roles, set as {} by default", userAccount.getName(), User.Role.USER);
+                userAccount.setRoles(User.Role.USER.toString());
+            }
+            userAccountRepository.put(userAccount.getName(), userAccount);
+        }
+    }
+
+    public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
+        if (userAccountRepository.containsKey(credentials.getUsername())
+            && EncryptorFactory.getPasswordEncryptor().checkPassword(credentials.getPassword(), userAccountRepository.get(credentials.getUsername()).getEncryptedPassword())) {
+            UserAccount userAccount = userAccountRepository.get(credentials.getUsername());
+            return Optional.of(new User(userAccount));
+        } else {
+            return Optional.absent();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/config/AuthenticationConfig.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/config/AuthenticationConfig.java b/eagle-server/src/main/java/org/apache/eagle/server/security/config/AuthenticationConfig.java
new file mode 100644
index 0000000..dbbb13b
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/config/AuthenticationConfig.java
@@ -0,0 +1,95 @@
+/*
+ * 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.eagle.server.security.config;
+
+import io.dropwizard.Configuration;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class AuthenticationConfig extends Configuration {
+    private boolean enabled = false;
+    private String mode = null;
+    private boolean caching = false;
+    private String cachePolicy = null;
+    private SimpleConfig simple = new SimpleConfig();
+    private LdapConfig ldap = new LdapConfig();
+
+    @JsonProperty
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @JsonProperty
+    public AuthenticationConfig setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        return this;
+    }
+
+    @JsonProperty
+    public String getMode() {
+        return mode;
+    }
+
+    @JsonProperty
+    public AuthenticationConfig setMode(String mode) {
+        this.mode = mode;
+        return this;
+    }
+
+    @JsonProperty
+    public boolean needsCaching() {
+        return caching;
+    }
+
+    @JsonProperty
+    public AuthenticationConfig setCaching(boolean caching) {
+        this.caching = caching;
+        return this;
+    }
+
+    @JsonProperty
+    public String getCachePolicy() {
+        return cachePolicy;
+    }
+
+    @JsonProperty
+    public AuthenticationConfig setCachePolicy(String cachePolicy) {
+        this.cachePolicy = cachePolicy;
+        return this;
+    }
+
+    @JsonProperty("ldap")
+    public LdapConfig getLdap() {
+        return ldap;
+    }
+
+    @JsonProperty("ldap")
+    public AuthenticationConfig setLdap(LdapConfig ldap) {
+        this.ldap = ldap;
+        return this;
+    }
+
+    @JsonProperty("simple")
+    public SimpleConfig getSimple() {
+        return simple;
+    }
+
+    @JsonProperty("simple")
+    public AuthenticationConfig setSimple(SimpleConfig simple) {
+        this.simple = simple;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/config/LdapConfig.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/config/LdapConfig.java b/eagle-server/src/main/java/org/apache/eagle/server/security/config/LdapConfig.java
new file mode 100644
index 0000000..c87553f
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/config/LdapConfig.java
@@ -0,0 +1,96 @@
+/*
+ * 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.eagle.server.security.config;
+
+import io.dropwizard.util.Duration;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class LdapConfig {
+
+    private String providerUrl = "";
+    private String strategy = "";
+    private String principalTemplate = "";
+    private String certificateAbsolutePath = "";
+    private Duration connectingTimeout = Duration.parse("500ms");
+    private Duration readingTimeout = Duration.parse("500ms");
+
+    @JsonProperty
+    public String getProviderUrl() {
+        return providerUrl;
+    }
+
+    @JsonProperty
+    public LdapConfig setProviderUrl(String providerUrl) {
+        this.providerUrl = providerUrl;
+        return this;
+    }
+
+    @JsonProperty
+    public String getPrincipalTemplate() {
+        return principalTemplate;
+    }
+
+    @JsonProperty
+    public LdapConfig setPrincipalTemplate(String principalTemplate) {
+        this.principalTemplate = principalTemplate;
+        return this;
+    }
+
+    @JsonProperty
+    public String getStrategy() {
+        return strategy;
+    }
+
+    @JsonProperty
+    public LdapConfig setStrategy(String strategy) {
+        this.strategy = strategy;
+        return this;
+    }
+
+    @JsonProperty
+    public Duration getConnectingTimeout() {
+        return connectingTimeout;
+    }
+
+    @JsonProperty
+    public LdapConfig setConnectingTimeout(Duration connectingTimeout) {
+        this.connectingTimeout = connectingTimeout;
+        return this;
+    }
+
+    @JsonProperty
+    public Duration getReadingTimeout() {
+        return readingTimeout;
+    }
+
+    @JsonProperty
+    public LdapConfig setReadingTimeout(Duration readingTimeout) {
+        this.readingTimeout = readingTimeout;
+        return this;
+    }
+
+    @JsonProperty
+    public String getCertificateAbsolutePath() {
+        return certificateAbsolutePath;
+    }
+
+    @JsonProperty
+    public LdapConfig setCertificateAbsolutePath(String certificateAbsolutePath) {
+        this.certificateAbsolutePath = certificateAbsolutePath;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/config/SimpleConfig.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/config/SimpleConfig.java b/eagle-server/src/main/java/org/apache/eagle/server/security/config/SimpleConfig.java
new file mode 100644
index 0000000..65ae10f
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/config/SimpleConfig.java
@@ -0,0 +1,34 @@
+/*
+ * 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.eagle.server.security.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.List;
+
+public class SimpleConfig {
+    private List<UserAccount> accounts;
+
+    @JsonProperty("accounts")
+    public List<UserAccount> getAccounts() {
+        return accounts;
+    }
+
+    public void setAccounts(List<UserAccount> accounts) {
+        this.accounts = accounts;
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/config/UserAccount.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/config/UserAccount.java b/eagle-server/src/main/java/org/apache/eagle/server/security/config/UserAccount.java
new file mode 100644
index 0000000..882e797
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/config/UserAccount.java
@@ -0,0 +1,55 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.security.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+import org.apache.eagle.common.security.User;
+
+import java.util.*;
+
+public class UserAccount extends User {
+
+    @JsonProperty("password")
+    public String getEncryptedPassword() {
+        return encryptedPassword;
+    }
+
+    private String encryptedPassword;
+
+    public UserAccount() {
+
+    }
+
+    public UserAccount(String username, String encryptedPassword) {
+        this.setName(username);
+        this.encryptedPassword = encryptedPassword;
+    }
+
+    public void setRoles(String roles) {
+        if (roles != null) {
+            String[] roleStrArray = roles.split(",");
+            Set<User.Role> rolesSet = new HashSet<>();
+            for (String roleStr:roleStrArray) {
+                User.Role role = User.Role.locateCaseInsensitive(roleStr.trim());
+                Preconditions.checkNotNull(role, "Invalid role " + roleStr);
+                rolesSet.add(role);
+            }
+            super.setRoles(rolesSet);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/EncryptorFactory.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/EncryptorFactory.java b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/EncryptorFactory.java
new file mode 100644
index 0000000..ff90213
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/EncryptorFactory.java
@@ -0,0 +1,23 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.security.encrypt;
+
+public class EncryptorFactory {
+    public static PasswordEncryptor getPasswordEncryptor() {
+        return new PasswordEncryptorImpl();
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptor.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptor.java b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptor.java
new file mode 100644
index 0000000..acf679e
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptor.java
@@ -0,0 +1,23 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.security.encrypt;
+
+public interface PasswordEncryptor {
+    String encryptPassword(String password);
+
+    boolean checkPassword(String password, String encryptedPassword);
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptorImpl.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptorImpl.java b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptorImpl.java
new file mode 100644
index 0000000..2c93c3c
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/security/encrypt/PasswordEncryptorImpl.java
@@ -0,0 +1,37 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.security.encrypt;
+
+import org.jasypt.util.password.StrongPasswordEncryptor;
+
+class PasswordEncryptorImpl implements PasswordEncryptor {
+    private final StrongPasswordEncryptor encryptor;
+
+    PasswordEncryptorImpl() {
+        this.encryptor = new StrongPasswordEncryptor();
+    }
+
+    @Override
+    public String encryptPassword(String password) {
+        return this.encryptor.encryptPassword(password);
+    }
+
+    @Override
+    public boolean checkPassword(String password, String encryptedPassword) {
+        return this.encryptor.checkPassword(password, encryptedPassword);
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/tool/EncryptTool.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/tool/EncryptTool.java b/eagle-server/src/main/java/org/apache/eagle/server/tool/EncryptTool.java
new file mode 100644
index 0000000..f77d90d
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/tool/EncryptTool.java
@@ -0,0 +1,42 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.tool;
+
+import org.apache.eagle.server.ServerMain;
+import org.apache.eagle.server.security.encrypt.EncryptorFactory;
+import org.apache.eagle.server.security.encrypt.PasswordEncryptor;
+
+public class EncryptTool implements Tool {
+
+    private static final String MISSING_TEXT =
+        "Error: require text to encrypt\n"
+        + "Usage: java " + ServerMain.class.getName() + " encrypt [text to encrypt]";
+
+    @Override
+    public void execute(String[] args) {
+        if (args.length < 2) {
+            System.err.println(MISSING_TEXT);
+        } else {
+            String textToEncrypt = args[1];
+            PasswordEncryptor encryptor = EncryptorFactory.getPasswordEncryptor();
+            String encryptedText = encryptor.encryptPassword(textToEncrypt);
+            System.out.println("Original: " + textToEncrypt);
+            System.out.println("Encrypted: " + encryptedText);
+            System.exit(0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/java/org/apache/eagle/server/tool/Tool.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/java/org/apache/eagle/server/tool/Tool.java b/eagle-server/src/main/java/org/apache/eagle/server/tool/Tool.java
new file mode 100644
index 0000000..bb5632a
--- /dev/null
+++ b/eagle-server/src/main/java/org/apache/eagle/server/tool/Tool.java
@@ -0,0 +1,21 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.server.tool;
+
+public interface Tool {
+    public void execute(String[] args);
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/main/resources/configuration.yml
----------------------------------------------------------------------
diff --git a/eagle-server/src/main/resources/configuration.yml b/eagle-server/src/main/resources/configuration.yml
index eabb8a1..a208f57 100644
--- a/eagle-server/src/main/resources/configuration.yml
+++ b/eagle-server/src/main/resources/configuration.yml
@@ -1,77 +1,74 @@
-# 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.
-
-server:
-  applicationConnectors:
-    - type: http
-      port: 9090
-  adminConnectors:
-    - type: http
-      port: 9091
-
-# ---------------------------------------------
-# Eagle Authentication Configuration
-# ---------------------------------------------
-auth:
-  # indicating if authentication is enabled, true for enabled, false for disabled
-  enabled: false
-
-  # indicating authentication mode, "simple" or "ldap"
-  mode: simple
-
-  # indicating whether to use cache: cache is usually used for authentications that may
-  # not handle high throughput (an RDBMS or LDAP server, for example)
-  caching: false
-
-  # indicating the cache policy, containing maximumSize and expireAfterWrite, e.g. maximumSize=10000, expireAfterWrite=10m
-  cachePolicy: maximumSize=10000, expireAfterWrite=1m
-
-  # indicating whether authorization is needed
-  authorization: false
-
-  # indicating whether @Auth annotation on parameters is needed
-  annotated: true
-
-  # for basic authentication, effective only when auth.mode=simple
-  simple:
-    # username for basic authentication, effective only when auth.mode=simple
-    username: admin
-    # password for basic authentication, effective only when auth.mode=simple
-    password: secret
-
-  # for ldap authentication, effective only when auth.mode=ldap
-  ldap:
-    # url providing ldap service. By convention, the port for typical ldap service is 389, and ldap service over ssl
-    # uses port 636 with protocol "ldaps", which requires certificates pre-installed.
-    providerUrl: ldap://server.address.or.domain:port
-
-    # template string containing ${USERNAME} placeholder. This is designed for some orgs who don't use plain usernames
-    # to authenticate, e.g. they may use its members' email address as the username: ${USERNAME}@some.org. When username
-    # is supposed to be recognized originally, just configure this parameter as ${USERNAME}
-    principalTemplate: ${USERNAME}@maybe.email.suffix
-
-    # string of strategy used by ldap service. "simple" is usually supported in most circumstances, we can use it by
-    # default or leave it a blank string.
-    strategy: simple
-
-    # the absolute path of ssl certificate file. This attribute is required conditional only when the auth -> mode is set
-    # as "ldap" and providerUrl starting with "ldaps://".
-    certificateAbsolutePath: /certificate/absolute/path
-
-    # timeout expression for connecting to ldap service endpoint
-    connectingTimeout: 500ms
-
-    # timeout expression for reading from ldap service
-    readingTimeout: 500ms
+# 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.
+
+server:
+  applicationConnectors:
+    - type: http
+      port: 9090
+  adminConnectors:
+    - type: http
+      port: 9091
+
+# ---------------------------------------------
+# Eagle Authentication Configuration
+# ---------------------------------------------
+auth:
+  # indicating if authentication is enabled, true for enabled, false for disabled
+  enabled: false
+
+  # indicating authentication mode, "simple" or "ldap"
+  mode: simple
+
+  # indicating whether to use cache: cache is usually used for authentications that may
+  # not handle high throughput (an RDBMS or LDAP server, for example)
+  caching: false
+
+  # indicating the cache policy, containing maximumSize and expireAfterWrite, e.g. maximumSize=10000, expireAfterWrite=10m
+  cachePolicy: maximumSize=10000, expireAfterWrite=1m
+
+  # for basic authentication, effective only when auth.mode=simple
+  simple:
+    accounts:
+      - name: admin
+        password: rWV/cdTCr01wTLBQ/rUilkExd2TJKrifXuCCTEwig1o08K8Mi0b1qQAgVXpPqflb
+        roles: ADMINISTRATOR
+        firstName: Admin
+        lastName: Admin
+        email: unknown-admin@eagle.apache.org
+
+  # for ldap authentication, effective only when auth.mode=ldap
+  ldap:
+    # url providing ldap service. By convention, the port for typical ldap service is 389, and ldap service over ssl
+    # uses port 636 with protocol "ldaps", which requires certificates pre-installed.
+    providerUrl: ldap://server.address.or.domain:port
+
+    # template string containing ${USERNAME} placeholder. This is designed for some orgs who don't use plain usernames
+    # to authenticate, e.g. they may use its members' email address as the name: ${USERNAME}@some.org. When name
+    # is supposed to be recognized originally, just configure this parameter as ${USERNAME}
+    principalTemplate: ${USERNAME}@maybe.email.suffix
+
+    # string of strategy used by ldap service. "simple" is usually supported in most circumstances, we can use it by
+    # default or leave it a blank string.
+    strategy: simple
+
+    # the absolute path of ssl certificate file. This attribute is required conditional only when the auth -> mode is set
+    # as "ldap" and providerUrl starting with "ldaps://".
+    certificateAbsolutePath: /certificate/absolute/path
+
+    # timeout expression for connecting to ldap service endpoint
+    connectingTimeout: 500ms
+
+    # timeout expression for reading from ldap service
+    readingTimeout: 500ms

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/ServerApplicationTest.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/ServerApplicationTest.java b/eagle-server/src/test/java/org/apache/eagle/server/ServerApplicationTest.java
deleted file mode 100644
index 6b299e5..0000000
--- a/eagle-server/src/test/java/org/apache/eagle/server/ServerApplicationTest.java
+++ /dev/null
@@ -1,26 +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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.eagle.server;
-
-import org.junit.Test;
-
-public class ServerApplicationTest {
-    @Test
-    public void testServerMain() throws Exception {
-        ServerMain.main(new String[] {"server", "src/test/resources/configuration.yml"});
-    }
-}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/ServerDebug.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/ServerDebug.java b/eagle-server/src/test/java/org/apache/eagle/server/ServerDebug.java
index f47f2bf..3225435 100644
--- a/eagle-server/src/test/java/org/apache/eagle/server/ServerDebug.java
+++ b/eagle-server/src/test/java/org/apache/eagle/server/ServerDebug.java
@@ -16,9 +16,11 @@
  */
 package org.apache.eagle.server;
 
+import org.junit.Ignore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Ignore
 public class ServerDebug {
     private static final Logger LOGGER = LoggerFactory.getLogger(ServerDebug.class);
     private static String serverConf = null;

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/LdapBasicAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/LdapBasicAuthenticatorTest.java b/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/LdapBasicAuthenticatorTest.java
deleted file mode 100644
index 8700a75..0000000
--- a/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/LdapBasicAuthenticatorTest.java
+++ /dev/null
@@ -1,168 +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.eagle.server.authentication.authenticator;
-
-import io.dropwizard.util.Duration;
-import org.apache.eagle.server.authentication.config.LdapSettings;
-import org.junit.Assert;
-import org.junit.Test;
-
-import javax.naming.Context;
-import java.util.Hashtable;
-
-public class LdapBasicAuthenticatorTest {
-
-    private static final String USERNAME_SUFFIX = "@some.emailbox.suffix";
-    private static final String USERNAME_TEMPLATE = "${USERNAME}" + USERNAME_SUFFIX;
-    private static final String LDAP_SERVICE_PROVIDER_URL = "ldap://some.address:port";
-    private static final String LDAP_SERVICE_PROVIDER_SSL_URL = "ldaps://some.address:port";
-    private static final String STRATEGY_SIMPLE = "customized";
-    private static final String CONNECTING_TIMEOUT_VALUE = "500ms";
-    private static final String READING_TIMEOUT_VALUE = "800ms";
-    private static final String LDAP_CTX_FACTORY_NAME = "com.sun.jndi.ldap.LdapCtxFactory";
-    private static final String LDAP_CONNECT_TIMEOUT_KEY = "com.sun.jndi.ldap.connect.timeout";
-    private static final String LDAP_READ_TIMEOUT_KEY = "com.sun.jndi.ldap.read.timeout";
-    private static final String SYS_PROP_SSL_KEY_STORE = "javax.net.ssl.keyStore";
-    private static final String SYS_PROP_SSL_TRUST_STORE = "javax.net.ssl.trustStore";
-    private static final String EXISTING_MOCK_FILE_PATH = String.format("%s/pom.xml", System.getProperty("user.dir"));
-    private static final LdapBasicAuthenticator AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL = new LdapBasicAuthenticator(
-            getNonSSLPreSettings().setPrincipalTemplate(USERNAME_TEMPLATE)
-                    .setStrategy(STRATEGY_SIMPLE)
-                    .setConnectingTimeout(Duration.parse(CONNECTING_TIMEOUT_VALUE))
-                    .setReadingTimeout(Duration.parse(READING_TIMEOUT_VALUE))
-    );
-    private static final LdapBasicAuthenticator AUTHENTICATOR_FOR_UTIL_METHODS_WITH_SSL = new LdapBasicAuthenticator(
-            getSSLPreSettings().setPrincipalTemplate(USERNAME_TEMPLATE)
-                    .setStrategy(STRATEGY_SIMPLE)
-                    .setCertificateAbsolutePath(EXISTING_MOCK_FILE_PATH)
-                    .setConnectingTimeout(Duration.parse(CONNECTING_TIMEOUT_VALUE))
-                    .setReadingTimeout(Duration.parse(READING_TIMEOUT_VALUE))
-    );
-
-    @Test
-    public void testSanitizeUsername() {
-        String correctUsername = "userNAME_123.45Z";
-        String sanitized = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.sanitizeUsername(correctUsername);
-        Assert.assertEquals(correctUsername, sanitized);
-
-        String incorrectUsername = "userNAME-~!@#$%^&777*()_+-=`[]\\{}|;':\",./<>?你";
-        sanitized = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.sanitizeUsername(incorrectUsername);
-        System.out.println(sanitized);
-        Assert.assertEquals("userNAME777_.", sanitized);
-    }
-
-    @Test
-    public void testComprisePrincipal() {
-        String username = "my.userNAME_123";
-        String principal = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.comprisePrincipal(username);
-        Assert.assertEquals(username+USERNAME_SUFFIX, principal);
-    }
-
-    @Test
-    public void testGetContextEnvironmentNormal() {
-        String username = "username";
-        String secretPhrase = "secret-phrase";
-        Hashtable<String, String> env = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.getContextEnvironment(username, secretPhrase);
-
-        Assert.assertEquals("unexpected ldap context factory name", LDAP_CTX_FACTORY_NAME, env.get(Context.INITIAL_CONTEXT_FACTORY));
-        Assert.assertEquals("unexpected ldap service provider url", LDAP_SERVICE_PROVIDER_URL, env.get(Context.PROVIDER_URL));
-        Assert.assertEquals("unexpected connecting timeout value", String.valueOf(Duration.parse(CONNECTING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_CONNECT_TIMEOUT_KEY));
-        Assert.assertEquals("unexpected reading timeout value", String.valueOf(Duration.parse(READING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_READ_TIMEOUT_KEY));
-        Assert.assertEquals("unexpected username", username+USERNAME_SUFFIX, env.get(Context.SECURITY_PRINCIPAL));
-        Assert.assertEquals("unexpected secret credentials", secretPhrase, env.get(Context.SECURITY_CREDENTIALS));
-        Assert.assertEquals("unexpected strategy", STRATEGY_SIMPLE, env.get(Context.SECURITY_AUTHENTICATION));
-    }
-
-    @Test
-    public void testGetContextEnvironmentBlankStrategy() {
-        String username = "username";
-        String secretPhrase = "secret-phrase";
-
-        // check strategy while it's configured as ""
-        LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getNonSSLPreSettings().setStrategy(""));
-        String strategyMaybeBlank = blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
-        Assert.assertNull("unexpected strategy", strategyMaybeBlank);
-    }
-
-    @Test
-    public void testGetContextEnvironmentNormalWithSSL() {
-        String username = "username";
-        String secretPhrase = "secret-phrase";
-        Hashtable<String, String> env = AUTHENTICATOR_FOR_UTIL_METHODS_WITH_SSL.getContextEnvironment(username, secretPhrase);
-
-        Assert.assertEquals("unexpected ldap context factory name", LDAP_CTX_FACTORY_NAME, env.get(Context.INITIAL_CONTEXT_FACTORY));
-        Assert.assertEquals("unexpected ldap service provider url", LDAP_SERVICE_PROVIDER_SSL_URL, env.get(Context.PROVIDER_URL));
-        Assert.assertEquals("unexpected connecting timeout value", String.valueOf(Duration.parse(CONNECTING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_CONNECT_TIMEOUT_KEY));
-        Assert.assertEquals("unexpected reading timeout value", String.valueOf(Duration.parse(READING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_READ_TIMEOUT_KEY));
-        Assert.assertEquals("unexpected username", username+USERNAME_SUFFIX, env.get(Context.SECURITY_PRINCIPAL));
-        Assert.assertEquals("unexpected secret credentials", secretPhrase, env.get(Context.SECURITY_CREDENTIALS));
-        Assert.assertEquals("unexpected strategy", STRATEGY_SIMPLE, env.get(Context.SECURITY_AUTHENTICATION));
-        Assert.assertEquals("unexpected key-store path", EXISTING_MOCK_FILE_PATH, System.getProperty(SYS_PROP_SSL_KEY_STORE));
-        Assert.assertEquals("unexpected trust-store path", EXISTING_MOCK_FILE_PATH, System.getProperty(SYS_PROP_SSL_TRUST_STORE));
-    }
-
-    @Test
-    public void testGetContextEnvironmentMeaninglessCAPathSSL() {
-        String username = "username";
-        String secretPhrase = "secret-phrase";
-
-        // check null certificateAbsolutePath
-        try {
-            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(null));
-            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
-        }
-        catch (Exception e) {
-            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
-            Assert.assertEquals("unexpected exception message", "The attribute 'certificateAbsolutePath' must be set when using ldap over ssl to authenticate.", e.getMessage());
-        }
-
-        // check "" certificateAbsolutePath
-        try {
-            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(""));
-            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
-        }
-        catch (Exception e) {
-            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
-            Assert.assertEquals("unexpected exception message", "The attribute 'certificateAbsolutePath' must be set when using ldap over ssl to authenticate.", e.getMessage());
-        }
-    }
-
-    @Test
-    public void testGetContextEnvironmentUnexistingCA_SSL() {
-        String username = "username";
-        String secretPhrase = "secret-phrase";
-        String wrongCAPath = String.format("%s/this/cannot/be/existing", System.getProperty("user.dir"));
-        try {
-            // check with not existing path indicated by certificateAbsolutePath
-            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(wrongCAPath));
-            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
-        }
-        catch (Exception e) {
-            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
-            Assert.assertEquals("unexpected exception message", String.format("The file specified not existing: %s", wrongCAPath), e.getMessage());
-        }
-    }
-
-    private static LdapSettings getNonSSLPreSettings() {
-        return new LdapSettings().setProviderUrl(LDAP_SERVICE_PROVIDER_URL);
-    }
-
-    private static LdapSettings getSSLPreSettings() {
-        return new LdapSettings().setProviderUrl(LDAP_SERVICE_PROVIDER_SSL_URL);
-    }
-}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/SimpleBasicAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/SimpleBasicAuthenticatorTest.java b/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/SimpleBasicAuthenticatorTest.java
deleted file mode 100644
index e896a7c..0000000
--- a/eagle-server/src/test/java/org/apache/eagle/server/authentication/authenticator/SimpleBasicAuthenticatorTest.java
+++ /dev/null
@@ -1,71 +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.eagle.server.authentication.authenticator;
-
-import com.google.common.base.Optional;
-import io.dropwizard.auth.AuthenticationException;
-import io.dropwizard.auth.basic.BasicCredentials;
-import org.apache.eagle.common.authentication.User;
-import org.apache.eagle.server.authentication.config.SimpleSettings;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SimpleBasicAuthenticatorTest {
-
-    private static final String TEST_USERNAME = "normal-username";
-    private static final String TEST_SECRET_PHRASE = "secret-phrase";
-    private static final String TEST_UNEXISTING_USERNAME = "unexisting-username";
-    private static final String TEST_WRONG_SECRET_PHRASE = "wrong-secret-phrase";
-    private static SimpleBasicAuthenticator authenticator = new SimpleBasicAuthenticator(new SimpleSettings().setUsername(TEST_USERNAME).setPassword(TEST_SECRET_PHRASE));
-
-    @Test
-    public void testNormal() {
-        try {
-            BasicCredentials credentials = new BasicCredentials(TEST_USERNAME, TEST_SECRET_PHRASE);
-            Optional<User> result = authenticator.authenticate(credentials);
-            Assert.assertTrue("result isn't present when passed correct credentials", result.isPresent());
-            User user = result.get();
-            Assert.assertEquals("authenticated user is not expected", TEST_USERNAME, user.getName());
-        }
-        catch (AuthenticationException e) {
-            Assert.fail("unexpected error occurs: "+e.getMessage());
-        }
-    }
-
-    @Test
-    public void testUnexistingUsername() {
-        try {
-            Optional<User> result = authenticator.authenticate(new BasicCredentials(TEST_UNEXISTING_USERNAME, TEST_SECRET_PHRASE));
-            Assert.assertFalse("result is present when passed unexisting username", result.isPresent());
-        }
-        catch (AuthenticationException e) {
-            Assert.fail("unexpected error occurs: "+e.getMessage());
-        }
-    }
-
-    @Test
-    public void testWrongPassword() {
-        try {
-            Optional<User> result = authenticator.authenticate(new BasicCredentials(TEST_USERNAME, TEST_WRONG_SECRET_PHRASE));
-            Assert.assertFalse("result is present when passed wrong password", result.isPresent());
-        }
-        catch (AuthenticationException e) {
-            Assert.fail("unexpected error occurs: "+e.getMessage());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/authentication/resource/TestBasicAuthenticationResource.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/authentication/resource/TestBasicAuthenticationResource.java b/eagle-server/src/test/java/org/apache/eagle/server/authentication/resource/TestBasicAuthenticationResource.java
deleted file mode 100644
index 0ea6666..0000000
--- a/eagle-server/src/test/java/org/apache/eagle/server/authentication/resource/TestBasicAuthenticationResource.java
+++ /dev/null
@@ -1,39 +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.eagle.server.authentication.resource;
-
-import io.dropwizard.auth.Auth;
-import org.apache.eagle.common.authentication.User;
-import org.apache.eagle.metadata.resource.RESTResponse;
-import org.junit.Ignore;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-@Ignore
-@Path("/test")
-public class TestBasicAuthenticationResource {
-    @GET
-    @Path("/ba/simple")
-    @Produces(MediaType.APPLICATION_JSON)
-    public RESTResponse<User> getIt(@Auth User user) {
-        return RESTResponse.<User>builder().data(user).success(true).status(Response.Status.OK).get();
-    }
-}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticatorTest.java b/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticatorTest.java
new file mode 100644
index 0000000..8389da8
--- /dev/null
+++ b/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/LdapBasicAuthenticatorTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.eagle.server.security.authenticator;
+
+import io.dropwizard.util.Duration;
+import org.apache.eagle.server.security.config.LdapConfig;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.naming.Context;
+import java.util.Hashtable;
+
+public class LdapBasicAuthenticatorTest {
+
+    private static final String USERNAME_SUFFIX = "@some.emailbox.suffix";
+    private static final String USERNAME_TEMPLATE = "${USERNAME}" + USERNAME_SUFFIX;
+    private static final String LDAP_SERVICE_PROVIDER_URL = "ldap://some.address:port";
+    private static final String LDAP_SERVICE_PROVIDER_SSL_URL = "ldaps://some.address:port";
+    private static final String STRATEGY_SIMPLE = "customized";
+    private static final String CONNECTING_TIMEOUT_VALUE = "500ms";
+    private static final String READING_TIMEOUT_VALUE = "800ms";
+    private static final String LDAP_CTX_FACTORY_NAME = "com.sun.jndi.ldap.LdapCtxFactory";
+    private static final String LDAP_CONNECT_TIMEOUT_KEY = "com.sun.jndi.ldap.connect.timeout";
+    private static final String LDAP_READ_TIMEOUT_KEY = "com.sun.jndi.ldap.read.timeout";
+    private static final String SYS_PROP_SSL_KEY_STORE = "javax.net.ssl.keyStore";
+    private static final String SYS_PROP_SSL_TRUST_STORE = "javax.net.ssl.trustStore";
+    private static final String EXISTING_MOCK_FILE_PATH = String.format("%s/pom.xml", System.getProperty("user.dir"));
+    private static final LdapBasicAuthenticator AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL = new LdapBasicAuthenticator(
+            getNonSSLPreSettings().setPrincipalTemplate(USERNAME_TEMPLATE)
+                    .setStrategy(STRATEGY_SIMPLE)
+                    .setConnectingTimeout(Duration.parse(CONNECTING_TIMEOUT_VALUE))
+                    .setReadingTimeout(Duration.parse(READING_TIMEOUT_VALUE))
+    );
+    private static final LdapBasicAuthenticator AUTHENTICATOR_FOR_UTIL_METHODS_WITH_SSL = new LdapBasicAuthenticator(
+            getSSLPreSettings().setPrincipalTemplate(USERNAME_TEMPLATE)
+                    .setStrategy(STRATEGY_SIMPLE)
+                    .setCertificateAbsolutePath(EXISTING_MOCK_FILE_PATH)
+                    .setConnectingTimeout(Duration.parse(CONNECTING_TIMEOUT_VALUE))
+                    .setReadingTimeout(Duration.parse(READING_TIMEOUT_VALUE))
+    );
+
+    @Test
+    public void testSanitizeUsername() {
+        String correctUsername = "userNAME_123.45Z";
+        String sanitized = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.sanitizeUsername(correctUsername);
+        Assert.assertEquals(correctUsername, sanitized);
+
+        String incorrectUsername = "userNAME-~!@#$%^&777*()_+-=`[]\\{}|;':\",./<>?你";
+        sanitized = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.sanitizeUsername(incorrectUsername);
+        System.out.println(sanitized);
+        Assert.assertEquals("userNAME777_.", sanitized);
+    }
+
+    @Test
+    public void testComprisePrincipal() {
+        String username = "my.userNAME_123";
+        String principal = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.comprisePrincipal(username);
+        Assert.assertEquals(username+USERNAME_SUFFIX, principal);
+    }
+
+    @Test
+    public void testGetContextEnvironmentNormal() {
+        String username = "username";
+        String secretPhrase = "secret-phrase";
+        Hashtable<String, String> env = AUTHENTICATOR_FOR_UTIL_METHODS_WITHOUT_SSL.getContextEnvironment(username, secretPhrase);
+
+        Assert.assertEquals("unexpected ldap context factory name", LDAP_CTX_FACTORY_NAME, env.get(Context.INITIAL_CONTEXT_FACTORY));
+        Assert.assertEquals("unexpected ldap service provider url", LDAP_SERVICE_PROVIDER_URL, env.get(Context.PROVIDER_URL));
+        Assert.assertEquals("unexpected connecting timeout value", String.valueOf(Duration.parse(CONNECTING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_CONNECT_TIMEOUT_KEY));
+        Assert.assertEquals("unexpected reading timeout value", String.valueOf(Duration.parse(READING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_READ_TIMEOUT_KEY));
+        Assert.assertEquals("unexpected username", username+USERNAME_SUFFIX, env.get(Context.SECURITY_PRINCIPAL));
+        Assert.assertEquals("unexpected secret credentials", secretPhrase, env.get(Context.SECURITY_CREDENTIALS));
+        Assert.assertEquals("unexpected strategy", STRATEGY_SIMPLE, env.get(Context.SECURITY_AUTHENTICATION));
+    }
+
+    @Test
+    public void testGetContextEnvironmentBlankStrategy() {
+        String username = "username";
+        String secretPhrase = "secret-phrase";
+
+        // check strategy while it's configured as ""
+        LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getNonSSLPreSettings().setStrategy(""));
+        String strategyMaybeBlank = blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
+        Assert.assertNull("unexpected strategy", strategyMaybeBlank);
+    }
+
+    @Test
+    public void testGetContextEnvironmentNormalWithSSL() {
+        String username = "username";
+        String secretPhrase = "secret-phrase";
+        Hashtable<String, String> env = AUTHENTICATOR_FOR_UTIL_METHODS_WITH_SSL.getContextEnvironment(username, secretPhrase);
+
+        Assert.assertEquals("unexpected ldap context factory name", LDAP_CTX_FACTORY_NAME, env.get(Context.INITIAL_CONTEXT_FACTORY));
+        Assert.assertEquals("unexpected ldap service provider url", LDAP_SERVICE_PROVIDER_SSL_URL, env.get(Context.PROVIDER_URL));
+        Assert.assertEquals("unexpected connecting timeout value", String.valueOf(Duration.parse(CONNECTING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_CONNECT_TIMEOUT_KEY));
+        Assert.assertEquals("unexpected reading timeout value", String.valueOf(Duration.parse(READING_TIMEOUT_VALUE).toMilliseconds()), env.get(LDAP_READ_TIMEOUT_KEY));
+        Assert.assertEquals("unexpected username", username+USERNAME_SUFFIX, env.get(Context.SECURITY_PRINCIPAL));
+        Assert.assertEquals("unexpected secret credentials", secretPhrase, env.get(Context.SECURITY_CREDENTIALS));
+        Assert.assertEquals("unexpected strategy", STRATEGY_SIMPLE, env.get(Context.SECURITY_AUTHENTICATION));
+        Assert.assertEquals("unexpected key-store path", EXISTING_MOCK_FILE_PATH, System.getProperty(SYS_PROP_SSL_KEY_STORE));
+        Assert.assertEquals("unexpected trust-store path", EXISTING_MOCK_FILE_PATH, System.getProperty(SYS_PROP_SSL_TRUST_STORE));
+    }
+
+    @Test
+    public void testGetContextEnvironmentMeaninglessCAPathSSL() {
+        String username = "username";
+        String secretPhrase = "secret-phrase";
+
+        // check null certificateAbsolutePath
+        try {
+            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(null));
+            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
+        }
+        catch (Exception e) {
+            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
+            Assert.assertEquals("unexpected exception message", "The attribute 'certificateAbsolutePath' must be set when using ldap over ssl to authenticate.", e.getMessage());
+        }
+
+        // check "" certificateAbsolutePath
+        try {
+            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(""));
+            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
+        }
+        catch (Exception e) {
+            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
+            Assert.assertEquals("unexpected exception message", "The attribute 'certificateAbsolutePath' must be set when using ldap over ssl to authenticate.", e.getMessage());
+        }
+    }
+
+    @Test
+    public void testGetContextEnvironmentUnexistingCA_SSL() {
+        String username = "username";
+        String secretPhrase = "secret-phrase";
+        String wrongCAPath = String.format("%s/this/cannot/be/existing", System.getProperty("user.dir"));
+        try {
+            // check with not existing path indicated by certificateAbsolutePath
+            LdapBasicAuthenticator blankStrategyAuthenticator = new LdapBasicAuthenticator(getSSLPreSettings().setCertificateAbsolutePath(wrongCAPath));
+            blankStrategyAuthenticator.getContextEnvironment(username, secretPhrase).get(Context.SECURITY_AUTHENTICATION);
+        }
+        catch (Exception e) {
+            Assert.assertEquals("unexpected exception thrown", RuntimeException.class, e.getClass());
+            Assert.assertEquals("unexpected exception message", String.format("The file specified not existing: %s", wrongCAPath), e.getMessage());
+        }
+    }
+
+    private static LdapConfig getNonSSLPreSettings() {
+        return new LdapConfig().setProviderUrl(LDAP_SERVICE_PROVIDER_URL);
+    }
+
+    private static LdapConfig getSSLPreSettings() {
+        return new LdapConfig().setProviderUrl(LDAP_SERVICE_PROVIDER_SSL_URL);
+    }
+}

http://git-wip-us.apache.org/repos/asf/eagle/blob/94b597b7/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticatorTest.java b/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticatorTest.java
new file mode 100644
index 0000000..8c638c5
--- /dev/null
+++ b/eagle-server/src/test/java/org/apache/eagle/server/security/authenticator/SimpleBasicAuthenticatorTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.eagle.server.security.authenticator;
+
+import com.google.common.base.Optional;
+import io.dropwizard.auth.AuthenticationException;
+import io.dropwizard.auth.basic.BasicCredentials;
+import org.apache.eagle.common.security.User;
+import org.apache.eagle.server.security.config.SimpleConfig;
+import org.apache.eagle.server.security.config.UserAccount;
+import org.apache.eagle.server.security.encrypt.EncryptorFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Collections;
+
+public class SimpleBasicAuthenticatorTest {
+
+    private static final String TEST_USERNAME = "normal-username";
+    private static final String TEST_SECRET_PHRASE = "secret-phrase";
+    private static final String TEST_UNEXISTING_USERNAME = "unexisting-username";
+    private static final String TEST_WRONG_SECRET_PHRASE = "wrong-secret-phrase";
+
+    private static SimpleConfig config = new SimpleConfig();
+
+    static {
+        config.setAccounts(Collections.singletonList(new UserAccount(TEST_USERNAME,
+            EncryptorFactory.getPasswordEncryptor().encryptPassword(TEST_SECRET_PHRASE))));
+    }
+
+    private static SimpleBasicAuthenticator authenticator = new SimpleBasicAuthenticator(config);
+
+    @Test
+    public void testNormal() {
+        try {
+            BasicCredentials credentials = new BasicCredentials(TEST_USERNAME, TEST_SECRET_PHRASE);
+            Optional<User> result = authenticator.authenticate(credentials);
+            Assert.assertTrue("result isn't present when passed correct credentials", result.isPresent());
+            User user = result.get();
+            Assert.assertEquals("authenticated user is not expected", TEST_USERNAME, user.getName());
+        } catch (AuthenticationException e) {
+            Assert.fail("unexpected error occurs: " + e.getMessage());
+        }
+    }
+
+    @Test
+    public void testUnexistingUsername() {
+        try {
+            Optional<User> result = authenticator.authenticate(new BasicCredentials(TEST_UNEXISTING_USERNAME, TEST_SECRET_PHRASE));
+            Assert.assertFalse("result is present when passed unexisting username", result.isPresent());
+        } catch (AuthenticationException e) {
+            Assert.fail("unexpected error occurs: " + e.getMessage());
+        }
+    }
+
+
+    @Test
+    public void testWrongPassword() {
+        try {
+            Optional<User> result = authenticator.authenticate(new BasicCredentials(TEST_USERNAME, TEST_WRONG_SECRET_PHRASE));
+            Assert.assertFalse("result is present when passed wrong password", result.isPresent());
+        } catch (AuthenticationException e) {
+            Assert.fail("unexpected error occurs: " + e.getMessage());
+        }
+    }
+}


Mime
View raw message