Search in sources :

Example 31 with AuthenticationResult

use of org.apache.druid.server.security.AuthenticationResult in project druid by druid-io.

the class DBCredentialsValidatorTest method validateMissingCredentials.

@Test
public void validateMissingCredentials() {
    String authenticatorName = "basic";
    String authorizerName = "basic";
    String username = "userB";
    String password = "helloworld";
    AuthenticationResult result = validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
    Assert.assertNull(result);
}
Also used : AuthenticationResult(org.apache.druid.server.security.AuthenticationResult) Test(org.junit.Test)

Example 32 with AuthenticationResult

use of org.apache.druid.server.security.AuthenticationResult in project druid by druid-io.

the class LDAPRoleProvider method getRoles.

@Override
public Set<String> getRoles(String authorizerPrefix, AuthenticationResult authenticationResult) {
    Set<String> roleNames = new HashSet<>();
    Map<String, BasicAuthorizerGroupMapping> groupMappingMap = cacheManager.getGroupMappingMap(authorizerPrefix);
    if (groupMappingMap == null) {
        throw new IAE("Could not load groupMappingMap for authorizer [%s]", authorizerPrefix);
    }
    Map<String, BasicAuthorizerUser> userMap = cacheManager.getUserMap(authorizerPrefix);
    if (userMap == null) {
        throw new IAE("Could not load userMap for authorizer [%s]", authorizerPrefix);
    }
    // Get the groups assigned to the LDAP user
    SearchResult searchResult = Optional.ofNullable(authenticationResult.getContext()).map(contextMap -> contextMap.get(BasicAuthUtils.SEARCH_RESULT_CONTEXT_KEY)).map(p -> {
        if (p instanceof SearchResult) {
            return (SearchResult) p;
        } else {
            return null;
        }
    }).orElse(null);
    if (searchResult != null) {
        try {
            Set<LdapName> groupNamesFromLdap = getGroupsFromLdap(searchResult);
            if (groupNamesFromLdap.isEmpty()) {
                LOG.debug("User %s is not mapped to any groups", authenticationResult.getIdentity());
            } else {
                // Get the roles mapped to LDAP groups from the metastore.
                // This allows us to authorize groups LDAP user belongs
                roleNames.addAll(getRoles(groupMappingMap, groupNamesFromLdap));
            }
        } catch (NamingException e) {
            LOG.error(e, "Exception in looking up groups for user %s", authenticationResult.getIdentity());
        }
    }
    // Get the roles assigned to LDAP user from the metastore.
    // This allow us to authorize LDAP users regardless of whether they belong to any groups or not in LDAP.
    BasicAuthorizerUser user = userMap.get(authenticationResult.getIdentity());
    if (user != null) {
        roleNames.addAll(user.getRoles());
    }
    return roleNames;
}
Also used : Logger(org.apache.druid.java.util.common.logger.Logger) JsonProperty(com.fasterxml.jackson.annotation.JsonProperty) Arrays(java.util.Arrays) LdapName(javax.naming.ldap.LdapName) BasicAuthorizerRole(org.apache.druid.security.basic.authorization.entity.BasicAuthorizerRole) BasicAuthUtils(org.apache.druid.security.basic.BasicAuthUtils) NamingException(javax.naming.NamingException) TreeSet(java.util.TreeSet) BasicAuthorizerUser(org.apache.druid.security.basic.authorization.entity.BasicAuthorizerUser) AuthenticationResult(org.apache.druid.server.security.AuthenticationResult) HashSet(java.util.HashSet) JsonTypeName(com.fasterxml.jackson.annotation.JsonTypeName) Attribute(javax.naming.directory.Attribute) Locale(java.util.Locale) Map(java.util.Map) IAE(org.apache.druid.java.util.common.IAE) JacksonInject(com.fasterxml.jackson.annotation.JacksonInject) BasicAuthorizerCacheManager(org.apache.druid.security.basic.authorization.db.cache.BasicAuthorizerCacheManager) RE(org.apache.druid.java.util.common.RE) StringUtils(org.apache.druid.java.util.common.StringUtils) Set(java.util.Set) InvalidNameException(javax.naming.InvalidNameException) JsonCreator(com.fasterxml.jackson.annotation.JsonCreator) Optional(java.util.Optional) VisibleForTesting(com.google.common.annotations.VisibleForTesting) BasicAuthorizerGroupMapping(org.apache.druid.security.basic.authorization.entity.BasicAuthorizerGroupMapping) SearchResult(javax.naming.directory.SearchResult) SearchResult(javax.naming.directory.SearchResult) IAE(org.apache.druid.java.util.common.IAE) LdapName(javax.naming.ldap.LdapName) BasicAuthorizerGroupMapping(org.apache.druid.security.basic.authorization.entity.BasicAuthorizerGroupMapping) BasicAuthorizerUser(org.apache.druid.security.basic.authorization.entity.BasicAuthorizerUser) NamingException(javax.naming.NamingException) HashSet(java.util.HashSet)

Example 33 with AuthenticationResult

use of org.apache.druid.server.security.AuthenticationResult in project druid by druid-io.

the class KerberosAuthenticator method getFilter.

@Override
public Filter getFilter() {
    return new AuthenticationFilter() {

        private Signer mySigner;

        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            ClassLoader prevLoader = Thread.currentThread().getContextClassLoader();
            try {
                // AuthenticationHandler is created during Authenticationfilter.init using reflection with thread context class loader.
                // In case of druid since the class is actually loaded as an extension and filter init is done in main thread.
                // We need to set the classloader explicitly to extension class loader.
                Thread.currentThread().setContextClassLoader(AuthenticationFilter.class.getClassLoader());
                super.init(filterConfig);
                String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX);
                configPrefix = (configPrefix != null) ? configPrefix + "." : "";
                Properties config = getConfiguration(configPrefix, filterConfig);
                String signatureSecret = config.getProperty(configPrefix + SIGNATURE_SECRET);
                if (signatureSecret == null) {
                    signatureSecret = Long.toString(ThreadLocalRandom.current().nextLong());
                    log.warn("'signature.secret' configuration not set, using a random value as secret");
                }
                final byte[] secretBytes = StringUtils.toUtf8(signatureSecret);
                SignerSecretProvider signerSecretProvider = new SignerSecretProvider() {

                    @Override
                    public void init(Properties config, ServletContext servletContext, long tokenValidity) {
                    }

                    @Override
                    public byte[] getCurrentSecret() {
                        return secretBytes;
                    }

                    @Override
                    public byte[][] getAllSecrets() {
                        return new byte[][] { secretBytes };
                    }
                };
                mySigner = new Signer(signerSecretProvider);
            } finally {
                Thread.currentThread().setContextClassLoader(prevLoader);
            }
        }

        // Copied from hadoop-auth's AuthenticationFilter, to allow us to change error response handling in doFilterSuper
        @Override
        protected AuthenticationToken getToken(HttpServletRequest request) throws AuthenticationException {
            AuthenticationToken token = null;
            String tokenStr = null;
            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals(AuthenticatedURL.AUTH_COOKIE)) {
                        tokenStr = cookie.getValue();
                        try {
                            tokenStr = mySigner.verifyAndExtract(tokenStr);
                        } catch (SignerException ex) {
                            throw new AuthenticationException(ex);
                        }
                        break;
                    }
                }
            }
            if (tokenStr != null) {
                token = AuthenticationToken.parse(tokenStr);
                if (!token.getType().equals(getAuthenticationHandler().getType())) {
                    throw new AuthenticationException("Invalid AuthenticationToken type");
                }
                if (token.isExpired()) {
                    throw new AuthenticationException("AuthenticationToken expired");
                }
            }
            return token;
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            // If there's already an auth result, then we have authenticated already, skip this.
            if (request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT) != null) {
                filterChain.doFilter(request, response);
                return;
            }
            // some other Authenticator didn't already validate this request.
            if (loginContext == null) {
                initializeKerberosLogin();
            }
            // Run the original doFilter method, but with modifications to error handling
            doFilterSuper(request, response, filterChain);
        }

        /**
         * Copied from hadoop-auth 2.7.3 AuthenticationFilter, to allow us to change error response handling.
         * Specifically, we want to defer the sending of 401 Unauthorized so that other Authenticators later in the chain
         * can check the request.
         */
        private void doFilterSuper(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            boolean unauthorizedResponse = true;
            int errCode = HttpServletResponse.SC_UNAUTHORIZED;
            AuthenticationException authenticationEx = null;
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            boolean isHttps = "https".equals(httpRequest.getScheme());
            try {
                boolean newToken = false;
                AuthenticationToken token;
                try {
                    token = getToken(httpRequest);
                } catch (AuthenticationException ex) {
                    log.warn("AuthenticationToken ignored: " + ex.getMessage());
                    // will be sent back in a 401 unless filter authenticates
                    authenticationEx = ex;
                    token = null;
                }
                if (getAuthenticationHandler().managementOperation(token, httpRequest, httpResponse)) {
                    if (token == null) {
                        if (log.isDebugEnabled()) {
                            log.debug("Request [{%s}] triggering authentication", getRequestURL(httpRequest));
                        }
                        token = getAuthenticationHandler().authenticate(httpRequest, httpResponse);
                        if (token != null && token.getExpires() != 0 && token != AuthenticationToken.ANONYMOUS) {
                            token.setExpires(System.currentTimeMillis() + getValidity() * 1000);
                        }
                        newToken = true;
                    }
                    if (token != null) {
                        unauthorizedResponse = false;
                        if (log.isDebugEnabled()) {
                            log.debug("Request [{%s}] user [{%s}] authenticated", getRequestURL(httpRequest), token.getUserName());
                        }
                        final AuthenticationToken authToken = token;
                        httpRequest = new HttpServletRequestWrapper(httpRequest) {

                            @Override
                            public String getAuthType() {
                                return authToken.getType();
                            }

                            @Override
                            public String getRemoteUser() {
                                return authToken.getUserName();
                            }

                            @Override
                            public Principal getUserPrincipal() {
                                return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null;
                            }
                        };
                        if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) {
                            String signedToken = mySigner.sign(token.toString());
                            tokenToAuthCookie(httpResponse, signedToken, getCookieDomain(), getCookiePath(), token.getExpires(), !token.isExpired() && token.getExpires() > 0, isHttps);
                            request.setAttribute(SIGNED_TOKEN_ATTRIBUTE, tokenToCookieString(signedToken, getCookieDomain(), getCookiePath(), token.getExpires(), !token.isExpired() && token.getExpires() > 0, isHttps));
                        }
                        // Since this request is validated also set DRUID_AUTHENTICATION_RESULT
                        request.setAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT, new AuthenticationResult(token.getName(), authorizerName, name, null));
                        doFilter(filterChain, httpRequest, httpResponse);
                    }
                } else {
                    unauthorizedResponse = false;
                }
            } catch (AuthenticationException ex) {
                // exception from the filter itself is fatal
                errCode = HttpServletResponse.SC_FORBIDDEN;
                authenticationEx = ex;
                if (log.isDebugEnabled()) {
                    log.debug(ex, "Authentication exception: " + ex.getMessage());
                } else {
                    log.warn("Authentication exception: " + ex.getMessage());
                }
            }
            if (unauthorizedResponse) {
                if (!httpResponse.isCommitted()) {
                    tokenToAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, false, isHttps);
                    // present.. reset to 403 if not found..
                    if ((errCode == HttpServletResponse.SC_UNAUTHORIZED) && (!httpResponse.containsHeader(org.apache.hadoop.security.authentication.client.KerberosAuthenticator.WWW_AUTHENTICATE))) {
                        errCode = HttpServletResponse.SC_FORBIDDEN;
                    }
                    if (authenticationEx == null) {
                        // Don't send an error response here, unlike the base AuthenticationFilter implementation.
                        // This request did not use Kerberos auth.
                        // Instead, we will send an error response in PreResponseAuthorizationCheckFilter to allow
                        // other Authenticator implementations to check the request.
                        filterChain.doFilter(request, response);
                    } else {
                        // Do send an error response here, we attempted Kerberos authentication and failed.
                        httpResponse.sendError(errCode, authenticationEx.getMessage());
                    }
                }
            }
        }
    };
}
Also used : SignerSecretProvider(org.apache.hadoop.security.authentication.util.SignerSecretProvider) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletRequest(javax.servlet.ServletRequest) AuthenticationToken(org.apache.hadoop.security.authentication.server.AuthenticationToken) AuthenticationException(org.apache.hadoop.security.authentication.client.AuthenticationException) FilterChain(javax.servlet.FilterChain) Properties(java.util.Properties) AuthenticationResult(org.apache.druid.server.security.AuthenticationResult) Signer(org.apache.hadoop.security.authentication.util.Signer) HttpServletRequest(javax.servlet.http.HttpServletRequest) HttpServletRequestWrapper(javax.servlet.http.HttpServletRequestWrapper) ServletContext(javax.servlet.ServletContext) FilterConfig(javax.servlet.FilterConfig) HttpCookie(java.net.HttpCookie) Cookie(javax.servlet.http.Cookie) ServletResponse(javax.servlet.ServletResponse) HttpServletResponse(javax.servlet.http.HttpServletResponse) AuthenticationFilter(org.apache.hadoop.security.authentication.server.AuthenticationFilter) HttpServletResponse(javax.servlet.http.HttpServletResponse) SignerException(org.apache.hadoop.security.authentication.util.SignerException) KerberosPrincipal(javax.security.auth.kerberos.KerberosPrincipal) Principal(java.security.Principal)

Example 34 with AuthenticationResult

use of org.apache.druid.server.security.AuthenticationResult in project druid by druid-io.

the class OverlordTest method setUp.

@Before
public void setUp() throws Exception {
    req = EasyMock.createMock(HttpServletRequest.class);
    EasyMock.expect(req.getAttribute(AuthConfig.DRUID_ALLOW_UNSECURED_PATH)).andReturn(null).anyTimes();
    EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).anyTimes();
    EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(new AuthenticationResult("druid", "druid", null, null)).anyTimes();
    req.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
    EasyMock.expectLastCall().anyTimes();
    supervisorManager = EasyMock.createMock(SupervisorManager.class);
    taskLockbox = EasyMock.createStrictMock(TaskLockbox.class);
    taskLockbox.syncFromStorage();
    EasyMock.expectLastCall().atLeastOnce();
    taskLockbox.add(EasyMock.anyObject());
    EasyMock.expectLastCall().atLeastOnce();
    taskLockbox.remove(EasyMock.anyObject());
    EasyMock.expectLastCall().atLeastOnce();
    // for second Noop Task directly added to deep storage.
    taskLockbox.add(EasyMock.anyObject());
    EasyMock.expectLastCall().atLeastOnce();
    taskLockbox.remove(EasyMock.anyObject());
    EasyMock.expectLastCall().atLeastOnce();
    taskActionClientFactory = EasyMock.createStrictMock(TaskActionClientFactory.class);
    EasyMock.expect(taskActionClientFactory.create(EasyMock.anyObject())).andReturn(null).anyTimes();
    EasyMock.replay(taskLockbox, taskActionClientFactory, req);
    taskStorage = new HeapMemoryTaskStorage(new TaskStorageConfig(null));
    runTaskCountDownLatches = new CountDownLatch[2];
    runTaskCountDownLatches[0] = new CountDownLatch(1);
    runTaskCountDownLatches[1] = new CountDownLatch(1);
    taskCompletionCountDownLatches = new CountDownLatch[2];
    taskCompletionCountDownLatches[0] = new CountDownLatch(1);
    taskCompletionCountDownLatches[1] = new CountDownLatch(1);
    announcementLatch = new CountDownLatch(1);
    setupServerAndCurator();
    curator.start();
    curator.blockUntilConnected();
    druidNode = new DruidNode("hey", "what", false, 1234, null, true, false);
    ServiceEmitter serviceEmitter = new NoopServiceEmitter();
    taskMaster = new TaskMaster(new TaskLockConfig(), new TaskQueueConfig(null, new Period(1), null, new Period(10)), new DefaultTaskConfig(), taskLockbox, taskStorage, taskActionClientFactory, druidNode, new TaskRunnerFactory<MockTaskRunner>() {

        @Override
        public MockTaskRunner build() {
            return new MockTaskRunner(runTaskCountDownLatches, taskCompletionCountDownLatches);
        }
    }, new NoopServiceAnnouncer() {

        @Override
        public void announce(DruidNode node) {
            announcementLatch.countDown();
        }
    }, new CoordinatorOverlordServiceConfig(null, null), serviceEmitter, supervisorManager, EasyMock.createNiceMock(OverlordHelperManager.class), new TestDruidLeaderSelector());
    EmittingLogger.registerEmitter(serviceEmitter);
}
Also used : ServiceEmitter(org.apache.druid.java.util.emitter.service.ServiceEmitter) NoopServiceEmitter(org.apache.druid.server.metrics.NoopServiceEmitter) CoordinatorOverlordServiceConfig(org.apache.druid.server.coordinator.CoordinatorOverlordServiceConfig) TaskStorageConfig(org.apache.druid.indexing.common.config.TaskStorageConfig) HeapMemoryTaskStorage(org.apache.druid.indexing.overlord.HeapMemoryTaskStorage) TaskActionClientFactory(org.apache.druid.indexing.common.actions.TaskActionClientFactory) Period(org.joda.time.Period) NoopServiceEmitter(org.apache.druid.server.metrics.NoopServiceEmitter) DefaultTaskConfig(org.apache.druid.indexing.overlord.config.DefaultTaskConfig) CountDownLatch(java.util.concurrent.CountDownLatch) TaskLockConfig(org.apache.druid.indexing.overlord.config.TaskLockConfig) AuthenticationResult(org.apache.druid.server.security.AuthenticationResult) HttpServletRequest(javax.servlet.http.HttpServletRequest) SupervisorManager(org.apache.druid.indexing.overlord.supervisor.SupervisorManager) TaskLockbox(org.apache.druid.indexing.overlord.TaskLockbox) TaskQueueConfig(org.apache.druid.indexing.overlord.config.TaskQueueConfig) DruidNode(org.apache.druid.server.DruidNode) TaskMaster(org.apache.druid.indexing.overlord.TaskMaster) NoopServiceAnnouncer(org.apache.druid.curator.discovery.NoopServiceAnnouncer) TaskRunnerFactory(org.apache.druid.indexing.overlord.TaskRunnerFactory) Before(org.junit.Before)

Example 35 with AuthenticationResult

use of org.apache.druid.server.security.AuthenticationResult in project druid by druid-io.

the class MetadataStoreCredentialsValidator method validateCredentials.

@Override
@Nullable
public AuthenticationResult validateCredentials(String authenticatorName, String authorizerName, String username, char[] password) {
    Map<String, BasicAuthenticatorUser> userMap = cacheManager.get().getUserMap(authenticatorName);
    if (userMap == null) {
        throw new IAE("No userMap is available for authenticator with prefix: [%s]", authenticatorName);
    }
    BasicAuthenticatorUser user = userMap.get(username);
    if (user == null) {
        return null;
    }
    BasicAuthenticatorCredentials credentials = user.getCredentials();
    if (credentials == null) {
        return null;
    }
    byte[] recalculatedHash = BasicAuthUtils.hashPassword(password, credentials.getSalt(), credentials.getIterations());
    if (Arrays.equals(recalculatedHash, credentials.getHash())) {
        return new AuthenticationResult(username, authorizerName, authenticatorName, null);
    } else {
        LOG.debug("Password incorrect for metadata store user %s", username);
        throw new BasicSecurityAuthenticationException("User metadata store authentication failed.");
    }
}
Also used : BasicSecurityAuthenticationException(org.apache.druid.security.basic.BasicSecurityAuthenticationException) BasicAuthenticatorCredentials(org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorCredentials) BasicAuthenticatorUser(org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorUser) IAE(org.apache.druid.java.util.common.IAE) AuthenticationResult(org.apache.druid.server.security.AuthenticationResult) Nullable(javax.annotation.Nullable)

Aggregations

AuthenticationResult (org.apache.druid.server.security.AuthenticationResult)58 Test (org.junit.Test)40 Response (javax.ws.rs.core.Response)25 Access (org.apache.druid.server.security.Access)17 HttpServletRequest (javax.servlet.http.HttpServletRequest)16 Resource (org.apache.druid.server.security.Resource)12 HashMap (java.util.HashMap)10 List (java.util.List)10 AuthConfig (org.apache.druid.server.security.AuthConfig)10 Authorizer (org.apache.druid.server.security.Authorizer)10 ImmutableList (com.google.common.collect.ImmutableList)9 Map (java.util.Map)9 HttpServletResponse (javax.servlet.http.HttpServletResponse)8 AuthorizerMapper (org.apache.druid.server.security.AuthorizerMapper)8 FilterChain (javax.servlet.FilterChain)7 Action (org.apache.druid.server.security.Action)7 ArrayList (java.util.ArrayList)6 Set (java.util.Set)6 TreeMap (java.util.TreeMap)6 DefaultObjectMapper (org.apache.druid.jackson.DefaultObjectMapper)6