001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.security.provider;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotSame;
022import static org.junit.Assert.assertSame;
023
024import java.io.IOException;
025import java.net.InetAddress;
026import java.util.HashMap;
027import java.util.Map;
028
029import javax.security.sasl.SaslClient;
030
031import org.apache.hadoop.conf.Configuration;
032import org.apache.hadoop.hbase.HBaseClassTestRule;
033import org.apache.hadoop.hbase.HBaseConfiguration;
034import org.apache.hadoop.hbase.security.SecurityInfo;
035import org.apache.hadoop.hbase.security.User;
036import org.apache.hadoop.hbase.testclassification.SecurityTests;
037import org.apache.hadoop.hbase.testclassification.SmallTests;
038import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
039import org.apache.hadoop.security.token.Token;
040import org.apache.hadoop.security.token.TokenIdentifier;
041import org.junit.ClassRule;
042import org.junit.Test;
043import org.junit.experimental.categories.Category;
044
045import org.apache.hadoop.hbase.shaded.protobuf.generated.RPCProtos.UserInformation;
046
047@Category({SmallTests.class, SecurityTests.class})
048public class TestSaslClientAuthenticationProviders {
049
050  @ClassRule
051  public static final HBaseClassTestRule CLASS_RULE =
052      HBaseClassTestRule.forClass(TestSaslClientAuthenticationProviders.class);
053
054  @Test
055  public void testCannotAddTheSameProviderTwice() {
056    HashMap<Byte,SaslClientAuthenticationProvider> registeredProviders = new HashMap<>();
057    SaslClientAuthenticationProvider p1 = new SimpleSaslClientAuthenticationProvider();
058    SaslClientAuthenticationProvider p2 = new SimpleSaslClientAuthenticationProvider();
059
060    SaslClientAuthenticationProviders.addProviderIfNotExists(p1, registeredProviders);
061    assertEquals(1, registeredProviders.size());
062
063    try {
064      SaslClientAuthenticationProviders.addProviderIfNotExists(p2, registeredProviders);
065    } catch (RuntimeException e) {}
066
067    assertSame("Expected the original provider to be present", p1,
068        registeredProviders.entrySet().iterator().next().getValue());
069  }
070
071  @Test
072  public void testInstanceIsCached() {
073    Configuration conf = HBaseConfiguration.create();
074    SaslClientAuthenticationProviders providers1 =
075        SaslClientAuthenticationProviders.getInstance(conf);
076    SaslClientAuthenticationProviders providers2 =
077        SaslClientAuthenticationProviders.getInstance(conf);
078    assertSame(providers1, providers2);
079
080    SaslClientAuthenticationProviders.reset();
081
082    SaslClientAuthenticationProviders providers3 =
083        SaslClientAuthenticationProviders.getInstance(conf);
084    assertNotSame(providers1, providers3);
085    assertEquals(providers1.getNumRegisteredProviders(), providers3.getNumRegisteredProviders());
086  }
087
088  @Test(expected = RuntimeException.class)
089  public void testDifferentConflictingImplementationsFail() {
090    Configuration conf = HBaseConfiguration.create();
091    conf.setStrings(SaslClientAuthenticationProviders.EXTRA_PROVIDERS_KEY,
092        ConflictingProvider1.class.getName(), ConflictingProvider2.class.getName());
093    SaslClientAuthenticationProviders.getInstance(conf);
094  }
095
096  static class ConflictingProvider1 implements SaslClientAuthenticationProvider {
097    static final SaslAuthMethod METHOD1 = new SaslAuthMethod(
098        "FOO", (byte)12, "DIGEST-MD5", AuthenticationMethod.SIMPLE);
099
100    public ConflictingProvider1() {
101    }
102
103    @Override public SaslAuthMethod getSaslAuthMethod() {
104      return METHOD1;
105    }
106
107    @Override public String getTokenKind() {
108      return null;
109    }
110
111    @Override public SaslClient createClient(Configuration conf, InetAddress serverAddr,
112        SecurityInfo securityInfo, Token<? extends TokenIdentifier> token, boolean fallbackAllowed,
113        Map<String, String> saslProps) throws IOException {
114      return null;
115    }
116
117    @Override public UserInformation getUserInfo(User user) {
118      return null;
119    }
120  }
121
122  static class ConflictingProvider2 implements SaslClientAuthenticationProvider {
123    static final SaslAuthMethod METHOD2 = new SaslAuthMethod(
124        "BAR", (byte)12, "DIGEST-MD5", AuthenticationMethod.SIMPLE);
125
126    public ConflictingProvider2() {
127    }
128
129    @Override public SaslAuthMethod getSaslAuthMethod() {
130      return METHOD2;
131    }
132
133    @Override public String getTokenKind() {
134      return null;
135    }
136
137    @Override public SaslClient createClient(Configuration conf, InetAddress serverAddr,
138        SecurityInfo securityInfo, Token<? extends TokenIdentifier> token, boolean fallbackAllowed,
139        Map<String, String> saslProps) throws IOException {
140      return null;
141    }
142
143    @Override public UserInformation getUserInfo(User user) {
144      return null;
145    }
146  }
147}