Coverage Report - org.apache.giraph.comm.netty.SaslNettyClient
 
Classes in this File Line Coverage Branch Coverage Complexity
SaslNettyClient
0%
0/41
0%
0/6
3.5
SaslNettyClient$SaslClientCallbackHandler
0%
0/31
0%
0/22
3.5
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 package org.apache.giraph.comm.netty;
 20  
 
 21  
 import org.apache.giraph.comm.requests.SaslTokenMessageRequest;
 22  
 import org.apache.hadoop.conf.Configuration;
 23  
 import org.apache.hadoop.mapred.JobConf;
 24  
 import org.apache.hadoop.mapreduce.security.TokenCache;
 25  
 import org.apache.hadoop.mapreduce.security.token.JobTokenIdentifier;
 26  
 import org.apache.hadoop.security.Credentials;
 27  
 /*if_not[STATIC_SASL_SYMBOL]*/
 28  
 import org.apache.hadoop.security.SaslPropertiesResolver;
 29  
 /*end[STATIC_SASL_SYMBOL]*/
 30  
 import org.apache.hadoop.security.SaslRpcServer;
 31  
 import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
 32  
 import org.apache.hadoop.security.token.Token;
 33  
 import org.apache.hadoop.security.token.TokenIdentifier;
 34  
 import org.apache.hadoop.security.UserGroupInformation;
 35  
 import org.apache.log4j.Logger;
 36  
 
 37  
 import javax.security.auth.callback.Callback;
 38  
 import javax.security.auth.callback.CallbackHandler;
 39  
 import javax.security.auth.callback.NameCallback;
 40  
 import javax.security.auth.callback.PasswordCallback;
 41  
 import javax.security.auth.callback.UnsupportedCallbackException;
 42  
 import javax.security.sasl.RealmCallback;
 43  
 import javax.security.sasl.RealmChoiceCallback;
 44  
 import javax.security.sasl.Sasl;
 45  
 import javax.security.sasl.SaslClient;
 46  
 import javax.security.sasl.SaslException;
 47  
 import java.io.IOException;
 48  
 
 49  
 /**
 50  
  * Implements SASL logic for Giraph BSP worker clients.
 51  
  */
 52  
 public class SaslNettyClient {
 53  
   /** Class logger */
 54  0
   public static final Logger LOG = Logger.getLogger(SaslNettyClient.class);
 55  
 
 56  
   /**
 57  
    * Used to synchronize client requests: client's work-related requests must
 58  
    * wait until SASL authentication completes.
 59  
    */
 60  0
   private Object authenticated = new Object();
 61  
 
 62  
   /**
 63  
    * Used to respond to server's counterpart, SaslServer with SASL tokens
 64  
    * represented as byte arrays.
 65  
    */
 66  
   private SaslClient saslClient;
 67  
 
 68  
   /**
 69  
    * Create a SaslNettyClient for authentication with BSP servers.
 70  
    */
 71  0
   public SaslNettyClient() {
 72  
     try {
 73  0
       Token<? extends TokenIdentifier> token =
 74  0
           createJobToken(new Configuration());
 75  0
       if (LOG.isDebugEnabled()) {
 76  0
         LOG.debug("SaslNettyClient: Creating SASL " +
 77  0
             AuthMethod.DIGEST.getMechanismName() +
 78  0
             " client to authenticate to service at " + token.getService());
 79  
       }
 80  
 /*if[STATIC_SASL_SYMBOL]
 81  
       saslClient =
 82  
           Sasl.createSaslClient(
 83  
               new String[] { AuthMethod.DIGEST.getMechanismName() }, null,
 84  
               null, SaslRpcServer.SASL_DEFAULT_REALM, SaslRpcServer.SASL_PROPS,
 85  
               new SaslClientCallbackHandler(token));
 86  
 else[STATIC_SASL_SYMBOL]*/
 87  0
       SaslPropertiesResolver saslPropsResolver =
 88  0
           SaslPropertiesResolver.getInstance(new Configuration());
 89  0
       saslClient =
 90  0
           Sasl.createSaslClient(
 91  0
               new String[] { AuthMethod.DIGEST.getMechanismName() }, null,
 92  
               null, SaslRpcServer.SASL_DEFAULT_REALM,
 93  0
               saslPropsResolver.getDefaultProperties(),
 94  
               new SaslClientCallbackHandler(token));
 95  
 /*end[STATIC_SASL_SYMBOL]*/
 96  0
     } catch (IOException e) {
 97  0
       LOG.error("SaslNettyClient: Could not obtain job token for Netty " +
 98  
           "Client to use to authenticate with a Netty Server.");
 99  0
       saslClient = null;
 100  0
     }
 101  0
   }
 102  
 
 103  
   public Object getAuthenticated() {
 104  0
     return authenticated;
 105  
   }
 106  
 
 107  
   /**
 108  
    * Obtain JobToken, which we'll use as a credential for SASL authentication
 109  
    * when connecting to other Giraph BSPWorkers.
 110  
    *
 111  
    * @param conf Configuration
 112  
    * @return a JobToken containing username and password so that client can
 113  
    * authenticate with a server.
 114  
    */
 115  
   private Token<JobTokenIdentifier> createJobToken(Configuration conf)
 116  
     throws IOException {
 117  0
     String localJobTokenFile = System.getenv().get(
 118  
         UserGroupInformation.HADOOP_TOKEN_FILE_LOCATION);
 119  0
     if (localJobTokenFile != null) {
 120  0
       JobConf jobConf = new JobConf(conf);
 121  0
       Credentials credentials =
 122  0
           TokenCache.loadTokens(localJobTokenFile, jobConf);
 123  0
       return TokenCache.getJobToken(credentials);
 124  
     } else {
 125  0
       throw new IOException("createJobToken: Cannot obtain authentication " +
 126  
           "credentials for job: file: '" +
 127  
           UserGroupInformation.HADOOP_TOKEN_FILE_LOCATION + "' not found");
 128  
     }
 129  
   }
 130  
 
 131  
   /**
 132  
    * Used by authenticateOnChannel() to initiate SASL handshake with server.
 133  
    * @return SaslTokenMessageRequest message to be sent to server.
 134  
    * @throws IOException
 135  
    */
 136  
   public SaslTokenMessageRequest firstToken()
 137  
     throws IOException {
 138  0
     byte[] saslToken = new byte[0];
 139  0
     if (saslClient.hasInitialResponse()) {
 140  0
       saslToken = saslClient.evaluateChallenge(saslToken);
 141  
     }
 142  0
     SaslTokenMessageRequest saslTokenMessage =
 143  
         new SaslTokenMessageRequest();
 144  0
     saslTokenMessage.setSaslToken(saslToken);
 145  0
     return saslTokenMessage;
 146  
   }
 147  
 
 148  
   public boolean isComplete() {
 149  0
     return saslClient.isComplete();
 150  
   }
 151  
 
 152  
   /**
 153  
    * Respond to server's SASL token.
 154  
    * @param saslTokenMessage contains server's SASL token
 155  
    * @return client's response SASL token
 156  
    */
 157  
   public byte[] saslResponse(SaslTokenMessageRequest saslTokenMessage) {
 158  
     try {
 159  0
       byte[] retval =
 160  0
           saslClient.evaluateChallenge(saslTokenMessage.getSaslToken());
 161  0
       return retval;
 162  0
     } catch (SaslException e) {
 163  0
       LOG.error("saslResponse: Failed to respond to SASL server's token:", e);
 164  0
       return null;
 165  
     }
 166  
   }
 167  
 
 168  
   /**
 169  
    * Implementation of javax.security.auth.callback.CallbackHandler
 170  
    * that works with Hadoop JobTokens.
 171  
    */
 172  
   private static class SaslClientCallbackHandler implements CallbackHandler {
 173  
     /** Generated username contained in JobToken */
 174  
     private final String userName;
 175  
     /** Generated password contained in JobToken */
 176  
     private final char[] userPassword;
 177  
 
 178  
     /**
 179  
      * Set private members using token.
 180  
      * @param token Hadoop JobToken.
 181  
      */
 182  0
     public SaslClientCallbackHandler(Token<? extends TokenIdentifier> token) {
 183  0
       this.userName = SaslNettyServer.encodeIdentifier(token.getIdentifier());
 184  0
       this.userPassword = SaslNettyServer.encodePassword(token.getPassword());
 185  0
     }
 186  
 
 187  
     /**
 188  
      * Implementation used to respond to SASL tokens from server.
 189  
      *
 190  
      * @param callbacks objects that indicate what credential information the
 191  
      *                  server's SaslServer requires from the client.
 192  
      * @throws UnsupportedCallbackException
 193  
      */
 194  
     public void handle(Callback[] callbacks)
 195  
       throws UnsupportedCallbackException {
 196  0
       NameCallback nc = null;
 197  0
       PasswordCallback pc = null;
 198  0
       RealmCallback rc = null;
 199  0
       for (Callback callback : callbacks) {
 200  0
         if (callback instanceof RealmChoiceCallback) {
 201  0
           continue;
 202  0
         } else if (callback instanceof NameCallback) {
 203  0
           nc = (NameCallback) callback;
 204  0
         } else if (callback instanceof PasswordCallback) {
 205  0
           pc = (PasswordCallback) callback;
 206  0
         } else if (callback instanceof RealmCallback) {
 207  0
           rc = (RealmCallback) callback;
 208  
         } else {
 209  0
           throw new UnsupportedCallbackException(callback,
 210  
               "handle: Unrecognized SASL client callback");
 211  
         }
 212  
       }
 213  0
       if (nc != null) {
 214  0
         if (LOG.isDebugEnabled()) {
 215  0
           LOG.debug("handle: SASL client callback: setting username: " +
 216  
               userName);
 217  
         }
 218  0
         nc.setName(userName);
 219  
       }
 220  0
       if (pc != null) {
 221  0
         if (LOG.isDebugEnabled()) {
 222  0
           LOG.debug("handle: SASL client callback: setting userPassword");
 223  
         }
 224  0
         pc.setPassword(userPassword);
 225  
       }
 226  0
       if (rc != null) {
 227  0
         if (LOG.isDebugEnabled()) {
 228  0
           LOG.debug("handle: SASL client callback: setting realm: " +
 229  0
               rc.getDefaultText());
 230  
         }
 231  0
         rc.setText(rc.getDefaultText());
 232  
       }
 233  0
     }
 234  
   }
 235  
 }