Github user agresch commented on a diff in the pull request:

    https://github.com/apache/storm/pull/2531#discussion_r164822325
  
    --- Diff: 
storm-client/src/jvm/org/apache/storm/security/auth/sasl/SimpleSaslServerCallbackHandler.java
 ---
    @@ -0,0 +1,179 @@
    +/**
    + * 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.storm.security.auth.sasl;
    +
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.List;
    +import java.util.Optional;
    +import javax.security.auth.callback.Callback;
    +import javax.security.auth.callback.CallbackHandler;
    +import javax.security.auth.callback.NameCallback;
    +import javax.security.auth.callback.PasswordCallback;
    +import javax.security.auth.callback.UnsupportedCallbackException;
    +import javax.security.sasl.AuthorizeCallback;
    +import javax.security.sasl.RealmCallback;
    +import org.apache.storm.security.auth.ReqContext;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +public class SimpleSaslServerCallbackHandler implements CallbackHandler {
    +    private static final Logger LOG = 
LoggerFactory.getLogger(SimpleSaslServerCallbackHandler.class);
    +    private final List<PasswordProvider> providers;
    +
    +    /**
    +     * Constructor with different password providers.
    +     * @param providers what will provide a password.  They will be 
checked in order, and the first one to
    +     *     return a password wins.
    +     */
    +    public SimpleSaslServerCallbackHandler(PasswordProvider ... providers) 
{
    +        this(Arrays.asList(providers));
    +    }
    +
    +    /**
    +     * Constructor with different password providers.
    +     * @param providers what will provide a password.  They will be 
checked in order, and the first one to
    +     *     return a password wins.
    +     */
    +    public SimpleSaslServerCallbackHandler(List<PasswordProvider> 
providers) {
    +        this.providers = new ArrayList<>(providers);
    +    }
    +
    +    private static void log(String type, AuthorizeCallback ac, 
NameCallback nc, PasswordCallback pc, RealmCallback rc) {
    +        if (LOG.isDebugEnabled()) {
    +            String acs = "null";
    +            if (ac != null) {
    +                acs = "athz: " + ac.getAuthorizationID() + " athn: " + 
ac.getAuthenticationID() + " authorized: " + ac.getAuthorizedID();
    +            }
    +
    +            String ncs = "null";
    +            if (nc != null) {
    +                ncs = "default: " + nc.getDefaultName() + " name: " + 
nc.getName();
    +            }
    +
    +            String pcs = "null";
    +            if (pc != null) {
    +                char[] pwd = pc.getPassword();
    +                pcs = "password: " + (pwd == null ? "null" : "not null " + 
pwd.length);
    +            }
    +
    +            String rcs = "null";
    +            if (rc != null) {
    +                rcs = "default: " + rc.getDefaultText() + " text: " + 
rc.getText();
    +            }
    +            LOG.debug("{}\nAC: {}\nNC: {}\nPC: {}\nRC: {}", type, acs, 
ncs, pcs, rcs);
    +        }
    +    }
    +
    +    private String translateName(String orig) {
    +        for (PasswordProvider provider: providers) {
    +            try {
    +                String ret = provider.userName(orig);
    +                if (ret != null) {
    +                    return ret;
    +                }
    +            } catch (Exception e) {
    +                LOG.debug("{} could not deserialize name {}", provider, 
orig, e);
    +            }
    +        }
    +        return orig;
    +    }
    +
    +    @Override
    +    public void handle(Callback[] callbacks) throws 
UnsupportedCallbackException, IOException {
    +        NameCallback nc = null;
    +        PasswordCallback pc = null;
    +        AuthorizeCallback ac = null;
    +        RealmCallback rc = null;
    +        for (Callback callback : callbacks) {
    +            if (callback instanceof AuthorizeCallback) {
    +                ac = (AuthorizeCallback) callback;
    +            } else if (callback instanceof NameCallback) {
    +                nc = (NameCallback) callback;
    +            } else if (callback instanceof PasswordCallback) {
    +                pc = (PasswordCallback) callback;
    +            } else if (callback instanceof RealmCallback) {
    +                rc = (RealmCallback) callback;
    +            } else {
    +                throw new UnsupportedCallbackException(callback,
    +                    "Unrecognized SASL Callback");
    +            }
    +        }
    +
    +        log("GOT", ac, nc, pc, rc);
    +
    +        if (nc != null) {
    +            String userName = nc.getDefaultName();
    +            boolean passwordFound = false;
    +            for (PasswordProvider provider : providers) {
    +                Optional<char[]> password = 
provider.getPasswordFor(userName);
    +                if (password.isPresent()) {
    +                    pc.setPassword(password.get());
    +                    nc.setName(provider.userName(userName));
    +                    passwordFound = true;
    +                    break;
    +                }
    +            }
    +            if (!passwordFound) {
    +                LOG.warn("No password found for user: {}", userName);
    +                throw new IOException("NOT ALLOWED.");
    +            }
    +        }
    +
    +        if (rc != null) {
    +            rc.setText(rc.getDefaultText());
    +        }
    +
    +        if (ac != null) {
    +            String nid = ac.getAuthenticationID();
    +            if (nid != null) {
    +                nid = translateName(nid);
    +            }
    +
    +            String zid = ac.getAuthorizationID();
    +            if (zid != null) {
    +                zid = translateName(zid);
    +            }
    +            LOG.info("Successfully authenticated client: authenticationID 
= {} authorizationID = {}",
    +                nid, zid);
    +
    +            //if authorizationId is not set, set it to authenticationId.
    +            if (zid == null) {
    +                ac.setAuthorizedID(nid);
    +                zid = nid;
    +            } else {
    +                ac.setAuthorizedID(zid);
    --- End diff --
    
    translateName may not have worked for zid (and nid) above (see other 
comment), and it is used here....  Can you explain (and add a comment) if that 
is acceptable and what behavior is going on when this occurs?


---

Reply via email to