|
| 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 | + * <p> |
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + * <p> |
| 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 | +package org.apache.ranger.authorization.credutils; |
| 19 | + |
| 20 | +import org.apache.http.auth.AuthScope; |
| 21 | +import org.apache.http.auth.Credentials; |
| 22 | +import org.apache.http.auth.UsernamePasswordCredentials; |
| 23 | +import org.apache.http.client.CredentialsProvider; |
| 24 | +import org.ietf.jgss.GSSCredential; |
| 25 | +import org.ietf.jgss.GSSException; |
| 26 | +import org.ietf.jgss.GSSManager; |
| 27 | +import org.ietf.jgss.GSSName; |
| 28 | +import org.ietf.jgss.Oid; |
| 29 | +import org.junit.jupiter.api.AfterEach; |
| 30 | +import org.junit.jupiter.api.BeforeEach; |
| 31 | +import org.junit.jupiter.api.MethodOrderer; |
| 32 | +import org.junit.jupiter.api.Test; |
| 33 | +import org.junit.jupiter.api.TestMethodOrder; |
| 34 | +import org.junit.jupiter.api.extension.ExtendWith; |
| 35 | +import org.mockito.MockedConstruction; |
| 36 | +import org.mockito.MockedStatic; |
| 37 | +import org.mockito.junit.jupiter.MockitoExtension; |
| 38 | + |
| 39 | +import javax.security.auth.Subject; |
| 40 | +import javax.security.auth.kerberos.KerberosPrincipal; |
| 41 | +import javax.security.auth.kerberos.KerberosTicket; |
| 42 | +import javax.security.auth.login.LoginContext; |
| 43 | +import javax.security.auth.login.LoginException; |
| 44 | + |
| 45 | +import java.security.AccessControlContext; |
| 46 | +import java.security.AccessController; |
| 47 | +import java.security.PrivilegedActionException; |
| 48 | +import java.security.PrivilegedExceptionAction; |
| 49 | +import java.util.Date; |
| 50 | + |
| 51 | +import static org.junit.jupiter.api.Assertions.assertEquals; |
| 52 | +import static org.junit.jupiter.api.Assertions.assertFalse; |
| 53 | +import static org.junit.jupiter.api.Assertions.assertInstanceOf; |
| 54 | +import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 55 | +import static org.junit.jupiter.api.Assertions.assertNull; |
| 56 | +import static org.junit.jupiter.api.Assertions.assertSame; |
| 57 | +import static org.junit.jupiter.api.Assertions.assertThrows; |
| 58 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
| 59 | +import static org.mockito.ArgumentMatchers.any; |
| 60 | +import static org.mockito.ArgumentMatchers.anyString; |
| 61 | +import static org.mockito.ArgumentMatchers.eq; |
| 62 | +import static org.mockito.Mockito.CALLS_REAL_METHODS; |
| 63 | +import static org.mockito.Mockito.doThrow; |
| 64 | +import static org.mockito.Mockito.mock; |
| 65 | +import static org.mockito.Mockito.mockConstruction; |
| 66 | +import static org.mockito.Mockito.mockStatic; |
| 67 | +import static org.mockito.Mockito.times; |
| 68 | +import static org.mockito.Mockito.verify; |
| 69 | +import static org.mockito.Mockito.when; |
| 70 | + |
| 71 | +/** |
| 72 | + * @generated by Cursor |
| 73 | + * @description : Unit Test cases for CredentialsProviderUtil |
| 74 | + */ |
| 75 | + |
| 76 | +@ExtendWith(MockitoExtension.class) |
| 77 | +@TestMethodOrder(MethodOrderer.MethodName.class) |
| 78 | +public class CredentialsProviderUtilTest { |
| 79 | + private MockedStatic<GSSManager> gssManagerStatic; |
| 80 | + private MockedStatic<AccessController> accessControllerStatic; |
| 81 | + |
| 82 | + @BeforeEach |
| 83 | + void setup() { |
| 84 | + CredentialsProviderUtil.ticketExpireTime80 = 0L; |
| 85 | + } |
| 86 | + |
| 87 | + @AfterEach |
| 88 | + void tearDown() { |
| 89 | + if (gssManagerStatic != null) { |
| 90 | + gssManagerStatic.close(); |
| 91 | + } |
| 92 | + if (accessControllerStatic != null) { |
| 93 | + accessControllerStatic.close(); |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + @Test |
| 98 | + void getBasicCredentials_setsUsernamePasswordOnAnyScope() { |
| 99 | + CredentialsProvider provider = CredentialsProviderUtil.getBasicCredentials("user", "pass"); |
| 100 | + Credentials creds = provider.getCredentials(AuthScope.ANY); |
| 101 | + assertNotNull(creds); |
| 102 | + assertInstanceOf(UsernamePasswordCredentials.class, creds); |
| 103 | + UsernamePasswordCredentials upc = (UsernamePasswordCredentials) creds; |
| 104 | + assertEquals("user", upc.getUserName()); |
| 105 | + assertEquals("pass", upc.getPassword()); |
| 106 | + } |
| 107 | + |
| 108 | + @Test |
| 109 | + void getKerberosCredentials_wrapsGssException() { |
| 110 | + GSSManager mockManager = mock(GSSManager.class); |
| 111 | + gssManagerStatic = mockStatic(GSSManager.class); |
| 112 | + gssManagerStatic.when(GSSManager::getInstance).thenReturn(mockManager); |
| 113 | + try { |
| 114 | + when(mockManager.createName(anyString(), any())).thenThrow(new GSSException(GSSException.FAILURE)); |
| 115 | + } catch (GSSException e) { |
| 116 | + // ignored |
| 117 | + } |
| 118 | + RuntimeException ex = assertThrows(RuntimeException.class, () -> CredentialsProviderUtil.getKerberosCredentials("user", "pw")); |
| 119 | + assertNotNull(ex.getCause()); |
| 120 | + } |
| 121 | + |
| 122 | + @Test |
| 123 | + void getKerberosCredentials_wrapsPrivilegedActionException() throws Exception { |
| 124 | + GSSManager mockManager = mock(GSSManager.class); |
| 125 | + gssManagerStatic = mockStatic(GSSManager.class); |
| 126 | + gssManagerStatic.when(GSSManager::getInstance).thenReturn(mockManager); |
| 127 | + GSSName mockName = mock(GSSName.class); |
| 128 | + when( mockManager. createName( eq( "[email protected]"), eq( GSSName. NT_USER_NAME))). thenReturn( mockName); |
| 129 | + when(mockManager.createCredential(eq(mockName), eq(GSSCredential.DEFAULT_LIFETIME), any(Oid.class), eq(GSSCredential.INITIATE_ONLY))).thenThrow(new GSSException(GSSException.FAILURE)); |
| 130 | + |
| 131 | + try (MockedStatic<CredentialsProviderUtil> cpu = mockStatic(CredentialsProviderUtil.class, CALLS_REAL_METHODS)) { |
| 132 | + Subject subject = new Subject(); |
| 133 | + cpu. when(() -> CredentialsProviderUtil. login( eq( "[email protected]"), eq( "/tmp/keytab"))). thenReturn( subject); |
| 134 | + |
| 135 | + RuntimeException ex = assertThrows( RuntimeException. class, () -> CredentialsProviderUtil. getKerberosCredentials( "[email protected]", "/tmp/keytab")); |
| 136 | + assertInstanceOf(PrivilegedActionException.class, ex.getCause()); |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + @Test |
| 141 | + void doAsPrivilegedWrapper_unwrapsNestedPrivilegedActionException() throws Exception { |
| 142 | + Subject subject = new Subject(); |
| 143 | + PrivilegedActionException inner = new PrivilegedActionException(new Exception("root")); |
| 144 | + PrivilegedExceptionAction<Object> action = () -> { |
| 145 | + throw inner; |
| 146 | + }; |
| 147 | + PrivilegedActionException thrown = assertThrows(PrivilegedActionException.class, () -> CredentialsProviderUtil.doAsPrivilegedWrapper(subject, action, mock(AccessControlContext.class))); |
| 148 | + assertInstanceOf(PrivilegedActionException.class, thrown.getCause()); |
| 149 | + assertInstanceOf(Exception.class, thrown.getCause().getCause()); |
| 150 | + assertEquals("root", thrown.getCause().getCause().getMessage()); |
| 151 | + } |
| 152 | + |
| 153 | + @Test |
| 154 | + void getTGT_returnsTicketMatchingTgtPattern() { |
| 155 | + Subject subject = new Subject(); |
| 156 | + KerberosPrincipal client = new KerberosPrincipal( "[email protected]"); |
| 157 | + KerberosPrincipal server = new KerberosPrincipal( "krbtgt/[email protected]"); |
| 158 | + Date now = new Date(); |
| 159 | + Date end = new Date(System.currentTimeMillis() + 60_000); |
| 160 | + Date renew = new Date(end.getTime() + 60_000); |
| 161 | + KerberosTicket tgt = new KerberosTicket(new byte[] {1}, client, server, new byte[] {1}, 1, null, now, now, end, renew, null); |
| 162 | + subject.getPrivateCredentials().add(tgt); |
| 163 | + |
| 164 | + KerberosTicket found = CredentialsProviderUtil.getTGT(subject); |
| 165 | + assertNotNull(found); |
| 166 | + assertEquals(server, found.getServer()); |
| 167 | + } |
| 168 | + |
| 169 | + @Test |
| 170 | + void ticketWillExpire_computes80PercentThresholdAndResets() { |
| 171 | + KerberosPrincipal client = new KerberosPrincipal( "[email protected]"); |
| 172 | + KerberosPrincipal server = new KerberosPrincipal( "krbtgt/[email protected]"); |
| 173 | + Date start = new Date(System.currentTimeMillis() - 1000); |
| 174 | + Date end = new Date(System.currentTimeMillis() + 10_000); |
| 175 | + Date renew = new Date(end.getTime() + 10_000); |
| 176 | + KerberosTicket ticket = new KerberosTicket(new byte[] {1}, client, server, new byte[] {1}, 1, null, start, start, end, renew, null); |
| 177 | + |
| 178 | + Boolean first = CredentialsProviderUtil.ticketWillExpire(ticket); |
| 179 | + assertFalse(first); |
| 180 | + CredentialsProviderUtil.ticketExpireTime80 = System.currentTimeMillis() - 1; |
| 181 | + Boolean second = CredentialsProviderUtil.ticketWillExpire(ticket); |
| 182 | + assertTrue(second); |
| 183 | + assertEquals(0L, CredentialsProviderUtil.ticketExpireTime80); |
| 184 | + } |
| 185 | + |
| 186 | + @Test |
| 187 | + void getTGT_returnsNullWhenNoTgt() { |
| 188 | + Subject subject = new Subject(); |
| 189 | + KerberosPrincipal client = new KerberosPrincipal( "[email protected]"); |
| 190 | + KerberosPrincipal server = new KerberosPrincipal( "HTTP/[email protected]"); |
| 191 | + Date now = new Date(); |
| 192 | + Date end = new Date(System.currentTimeMillis() + 60_000); |
| 193 | + Date renew = new Date(end.getTime() + 60_000); |
| 194 | + KerberosTicket notTgt = new KerberosTicket(new byte[] {1}, client, server, new byte[] {1}, 1, null, now, now, end, renew, null); |
| 195 | + subject.getPrivateCredentials().add(notTgt); |
| 196 | + |
| 197 | + assertNull(CredentialsProviderUtil.getTGT(subject)); |
| 198 | + } |
| 199 | + |
| 200 | + @Test |
| 201 | + void login_success_returnsSubjectFromLoginContext() throws Exception { |
| 202 | + Subject subject = new Subject(); |
| 203 | + try (MockedConstruction<LoginContext> mocked = mockConstruction(LoginContext.class, (mock, context) -> { |
| 204 | + when(mock.getSubject()).thenReturn(subject); |
| 205 | + })) { |
| 206 | + Subject out = CredentialsProviderUtil. login( "[email protected]", "/tmp/user.keytab"); |
| 207 | + assertSame(subject, out); |
| 208 | + verify(mocked.constructed().get(0), times(1)).login(); |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + @Test |
| 213 | + void login_throwsPrivilegedActionException_whenLoginContextFails() throws Exception { |
| 214 | + try (MockedConstruction<LoginContext> mocked = mockConstruction(LoginContext.class, (mock, context) -> { |
| 215 | + doThrow(new LoginException("boom")).when(mock).login(); |
| 216 | + })) { |
| 217 | + PrivilegedActionException pae = assertThrows( PrivilegedActionException. class, () -> CredentialsProviderUtil. login( "[email protected]", "/tmp/user.keytab")); |
| 218 | + assertTrue(pae.getException() instanceof LoginException); |
| 219 | + assertEquals("boom", pae.getException().getMessage()); |
| 220 | + } |
| 221 | + } |
| 222 | +} |
0 commit comments