private void checkUgiFromToken(UserGroupInformation ugi) { if (ugi.getRealUser() != null) { Assert.assertEquals(AuthenticationMethod.PROXY, ugi.getAuthenticationMethod()); Assert.assertEquals(AuthenticationMethod.TOKEN, ugi.getRealUser().getAuthenticationMethod()); } else { Assert.assertEquals(AuthenticationMethod.TOKEN, ugi.getAuthenticationMethod()); } }
@Test public void testGetNonProxyUgi() throws IOException { conf.set(DFSConfigKeys.FS_DEFAULT_NAME_KEY, "hdfs://localhost:4321/"); ServletContext context = mock(ServletContext.class); String realUser = "******"; String user = "******"; conf.set(DFSConfigKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); UserGroupInformation.setConfiguration(conf); UserGroupInformation ugi; HttpServletRequest request; // have to be auth-ed with remote user request = getMockRequest(null, null, null); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Security enabled but user not authenticated by filter", ioe.getMessage()); } request = getMockRequest(null, realUser, null); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Security enabled but user not authenticated by filter", ioe.getMessage()); } // ugi for remote user request = getMockRequest(realUser, null, null); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNull(ugi.getRealUser()); Assert.assertEquals(ugi.getShortUserName(), realUser); checkUgiFromAuth(ugi); // ugi for remote user = real user request = getMockRequest(realUser, realUser, null); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNull(ugi.getRealUser()); Assert.assertEquals(ugi.getShortUserName(), realUser); checkUgiFromAuth(ugi); // ugi for remote user != real user request = getMockRequest(realUser, user, null); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Usernames not matched: name=" + user + " != expected=" + realUser, ioe.getMessage()); } }
/** * @param ugi A user group information. * @return true if delegation token operation is allowed */ private boolean isAllowedDelegationTokenOp(UserGroupInformation ugi) throws IOException { AuthenticationMethod authMethod = ugi.getAuthenticationMethod(); if (authMethod == AuthenticationMethod.PROXY) { authMethod = ugi.getRealUser().getAuthenticationMethod(); } if (authMethod != AuthenticationMethod.KERBEROS && authMethod != AuthenticationMethod.KERBEROS_SSL && authMethod != AuthenticationMethod.CERTIFICATE) { return false; } return true; }
@Test(timeout = 60000) public void testSimpleProxyAuthParamsInUrl() throws IOException { Configuration conf = new Configuration(); UserGroupInformation ugi = UserGroupInformation.createRemoteUser("test-user"); ugi = UserGroupInformation.createProxyUser("test-proxy-user", ugi); UserGroupInformation.setLoginUser(ugi); WebHdfsFileSystem webhdfs = getWebHdfsFileSystem(ugi, conf); Path fsPath = new Path("/"); // send real+effective URL fileStatusUrl = webhdfs.toUrl(GetOpParam.Op.GETFILESTATUS, fsPath); checkQueryParams( new String[] { GetOpParam.Op.GETFILESTATUS.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString() }, fileStatusUrl); }
@Test(timeout = 60000) public void testSecureProxyAuthParamsInUrl() throws IOException { Configuration conf = new Configuration(); // fake turning on security so api thinks it should use tokens SecurityUtil.setAuthenticationMethod(KERBEROS, conf); UserGroupInformation.setConfiguration(conf); UserGroupInformation ugi = UserGroupInformation.createRemoteUser("test-user"); ugi.setAuthenticationMethod(KERBEROS); ugi = UserGroupInformation.createProxyUser("test-proxy-user", ugi); UserGroupInformation.setLoginUser(ugi); WebHdfsFileSystem webhdfs = getWebHdfsFileSystem(ugi, conf); Path fsPath = new Path("/"); String tokenString = webhdfs.getDelegationToken().encodeToUrlString(); // send real+effective URL getTokenUrl = webhdfs.toUrl(GetOpParam.Op.GETDELEGATIONTOKEN, fsPath); checkQueryParams( new String[] { GetOpParam.Op.GETDELEGATIONTOKEN.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString() }, getTokenUrl); // send real+effective URL renewTokenUrl = webhdfs.toUrl( PutOpParam.Op.RENEWDELEGATIONTOKEN, fsPath, new TokenArgumentParam(tokenString)); checkQueryParams( new String[] { PutOpParam.Op.RENEWDELEGATIONTOKEN.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString(), new TokenArgumentParam(tokenString).toString(), }, renewTokenUrl); // send token URL cancelTokenUrl = webhdfs.toUrl( PutOpParam.Op.CANCELDELEGATIONTOKEN, fsPath, new TokenArgumentParam(tokenString)); checkQueryParams( new String[] { PutOpParam.Op.CANCELDELEGATIONTOKEN.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString(), new TokenArgumentParam(tokenString).toString(), }, cancelTokenUrl); // send token URL fileStatusUrl = webhdfs.toUrl(GetOpParam.Op.GETFILESTATUS, fsPath); checkQueryParams( new String[] { GetOpParam.Op.GETFILESTATUS.toQueryString(), new DelegationParam(tokenString).toString() }, fileStatusUrl); // wipe out internal token to simulate auth always required webhdfs.setDelegationToken(null); // send real+effective cancelTokenUrl = webhdfs.toUrl( PutOpParam.Op.CANCELDELEGATIONTOKEN, fsPath, new TokenArgumentParam(tokenString)); checkQueryParams( new String[] { PutOpParam.Op.CANCELDELEGATIONTOKEN.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString(), new TokenArgumentParam(tokenString).toString() }, cancelTokenUrl); // send real+effective fileStatusUrl = webhdfs.toUrl(GetOpParam.Op.GETFILESTATUS, fsPath); checkQueryParams( new String[] { GetOpParam.Op.GETFILESTATUS.toQueryString(), new UserParam(ugi.getRealUser().getShortUserName()).toString(), new DoAsParam(ugi.getShortUserName()).toString() }, fileStatusUrl); }
@Test public void testGetProxyUgi() throws IOException { conf.set(DFSConfigKeys.FS_DEFAULT_NAME_KEY, "hdfs://localhost:4321/"); ServletContext context = mock(ServletContext.class); String realUser = "******"; String user = "******"; conf.set(DFSConfigKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); conf.set(DefaultImpersonationProvider.getProxySuperuserGroupConfKey(realUser), "*"); conf.set(DefaultImpersonationProvider.getProxySuperuserIpConfKey(realUser), "*"); ProxyUsers.refreshSuperUserGroupsConfiguration(conf); UserGroupInformation.setConfiguration(conf); UserGroupInformation ugi; HttpServletRequest request; // have to be auth-ed with remote user request = getMockRequest(null, null, user); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Security enabled but user not authenticated by filter", ioe.getMessage()); } request = getMockRequest(null, realUser, user); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Security enabled but user not authenticated by filter", ioe.getMessage()); } // proxy ugi for user via remote user request = getMockRequest(realUser, null, user); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromAuth(ugi); // proxy ugi for user vi a remote user = real user request = getMockRequest(realUser, realUser, user); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromAuth(ugi); // proxy ugi for user via remote user != real user request = getMockRequest(realUser, user, user); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Usernames not matched: name=" + user + " != expected=" + realUser, ioe.getMessage()); } // try to get get a proxy user with unauthorized user try { request = getMockRequest(user, null, realUser); JspHelper.getUGI(context, request, conf); Assert.fail("bad proxy request allowed"); } catch (AuthorizationException ae) { Assert.assertEquals( "User: "******" is not allowed to impersonate " + realUser, ae.getMessage()); } try { request = getMockRequest(user, user, realUser); JspHelper.getUGI(context, request, conf); Assert.fail("bad proxy request allowed"); } catch (AuthorizationException ae) { Assert.assertEquals( "User: "******" is not allowed to impersonate " + realUser, ae.getMessage()); } }
@Test public void testGetUgiFromToken() throws IOException { conf.set(DFSConfigKeys.FS_DEFAULT_NAME_KEY, "hdfs://localhost:4321/"); ServletContext context = mock(ServletContext.class); String realUser = "******"; String user = "******"; conf.set(DFSConfigKeys.HADOOP_SECURITY_AUTHENTICATION, "kerberos"); UserGroupInformation.setConfiguration(conf); UserGroupInformation ugi; HttpServletRequest request; Text ownerText = new Text(user); DelegationTokenIdentifier dtId = new DelegationTokenIdentifier(ownerText, ownerText, new Text(realUser)); Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(dtId, new DummySecretManager(0, 0, 0, 0)); String tokenString = token.encodeToUrlString(); // token with no auth-ed user request = getMockRequest(null, null, null); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromToken(ugi); // token with auth-ed user request = getMockRequest(realUser, null, null); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromToken(ugi); // completely different user, token trumps auth request = getMockRequest("rogue", null, null); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromToken(ugi); // expected case request = getMockRequest(null, user, null); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); ugi = JspHelper.getUGI(context, request, conf); Assert.assertNotNull(ugi.getRealUser()); Assert.assertEquals(ugi.getRealUser().getShortUserName(), realUser); Assert.assertEquals(ugi.getShortUserName(), user); checkUgiFromToken(ugi); // can't proxy with a token! request = getMockRequest(null, null, "rogue"); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Usernames not matched: name=rogue != expected=" + user, ioe.getMessage()); } // can't proxy with a token! request = getMockRequest(null, user, "rogue"); when(request.getParameter(JspHelper.DELEGATION_PARAMETER_NAME)).thenReturn(tokenString); try { JspHelper.getUGI(context, request, conf); Assert.fail("bad request allowed"); } catch (IOException ioe) { Assert.assertEquals( "Usernames not matched: name=rogue != expected=" + user, ioe.getMessage()); } }
/** * Get {@link UserGroupInformation} and possibly the delegation token out of the request. * * @param context the Servlet context * @param request the http request * @param conf configuration * @param secureAuthMethod the AuthenticationMethod used in secure mode. * @param tryUgiParameter Should it try the ugi parameter? * @return a new user from the request * @throws AccessControlException if the request has no token */ public static UserGroupInformation getUGI( ServletContext context, HttpServletRequest request, Configuration conf, final AuthenticationMethod secureAuthMethod, final boolean tryUgiParameter) throws IOException { final UserGroupInformation ugi; final String usernameFromQuery = getUsernameFromQuery(request, tryUgiParameter); final String doAsUserFromQuery = request.getParameter(DoAsParam.NAME); if (UserGroupInformation.isSecurityEnabled()) { final String remoteUser = request.getRemoteUser(); String tokenString = request.getParameter(DELEGATION_PARAMETER_NAME); if (tokenString != null) { Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(); token.decodeFromUrlString(tokenString); SecurityUtil.setTokenService(token, NameNode.getAddress(conf)); token.setKind(DelegationTokenIdentifier.HDFS_DELEGATION_KIND); ByteArrayInputStream buf = new ByteArrayInputStream(token.getIdentifier()); DataInputStream in = new DataInputStream(buf); DelegationTokenIdentifier id = new DelegationTokenIdentifier(); id.readFields(in); if (context != null) { NameNode nn = (NameNode) context.getAttribute("name.node"); if (nn != null) { // Verify the token. nn.getNamesystem() .getDelegationTokenSecretManager() .verifyToken(id, token.getPassword()); } } ugi = id.getUser(); if (ugi.getRealUser() == null) { // non-proxy case checkUsername(ugi.getShortUserName(), usernameFromQuery); checkUsername(null, doAsUserFromQuery); } else { // proxy case checkUsername(ugi.getRealUser().getShortUserName(), usernameFromQuery); checkUsername(ugi.getShortUserName(), doAsUserFromQuery); ProxyUsers.authorize(ugi, request.getRemoteAddr(), conf); } ugi.addToken(token); ugi.setAuthenticationMethod(AuthenticationMethod.TOKEN); } else { if (remoteUser == null) { throw new IOException("Security enabled but user not " + "authenticated by filter"); } final UserGroupInformation realUgi = UserGroupInformation.createRemoteUser(remoteUser); checkUsername(realUgi.getShortUserName(), usernameFromQuery); // This is not necessarily true, could have been auth'ed by user-facing // filter realUgi.setAuthenticationMethod(secureAuthMethod); ugi = initUGI(realUgi, doAsUserFromQuery, request, true, conf); } } else { // Security's not on, pull from url final UserGroupInformation realUgi = usernameFromQuery == null ? getDefaultWebUser(conf) // not specified in request : UserGroupInformation.createRemoteUser(usernameFromQuery); realUgi.setAuthenticationMethod(AuthenticationMethod.SIMPLE); ugi = initUGI(realUgi, doAsUserFromQuery, request, false, conf); } if (LOG.isDebugEnabled()) LOG.debug("getUGI is returning: " + ugi.getShortUserName()); return ugi; }
@Test public void testRefreshSuperUserGroupsConfiguration() throws Exception { final String SUPER_USER = "******"; final String[] GROUP_NAMES1 = new String[] {"gr1", "gr2"}; final String[] GROUP_NAMES2 = new String[] {"gr3", "gr4"}; // keys in conf String userKeyGroups = ProxyUsers.getProxySuperuserGroupConfKey(SUPER_USER); String userKeyHosts = ProxyUsers.getProxySuperuserIpConfKey(SUPER_USER); config.set(userKeyGroups, "gr3,gr4,gr5"); // superuser can proxy for this group config.set(userKeyHosts, "127.0.0.1"); ProxyUsers.refreshSuperUserGroupsConfiguration(config); UserGroupInformation ugi1 = mock(UserGroupInformation.class); UserGroupInformation ugi2 = mock(UserGroupInformation.class); UserGroupInformation suUgi = mock(UserGroupInformation.class); when(ugi1.getRealUser()).thenReturn(suUgi); when(ugi2.getRealUser()).thenReturn(suUgi); when(suUgi.getShortUserName()).thenReturn(SUPER_USER); // super user when(suUgi.getUserName()).thenReturn(SUPER_USER + "L"); // super user when(ugi1.getShortUserName()).thenReturn("user1"); when(ugi2.getShortUserName()).thenReturn("user2"); when(ugi1.getUserName()).thenReturn("userL1"); when(ugi2.getUserName()).thenReturn("userL2"); // set groups for users when(ugi1.getGroupNames()).thenReturn(GROUP_NAMES1); when(ugi2.getGroupNames()).thenReturn(GROUP_NAMES2); // check before try { ProxyUsers.authorize(ugi1, "127.0.0.1", config); fail("first auth for " + ugi1.getShortUserName() + " should've failed "); } catch (AuthorizationException e) { // expected System.err.println("auth for " + ugi1.getUserName() + " failed"); } try { ProxyUsers.authorize(ugi2, "127.0.0.1", config); System.err.println("auth for " + ugi2.getUserName() + " succeeded"); // expected } catch (AuthorizationException e) { fail( "first auth for " + ugi2.getShortUserName() + " should've succeeded: " + e.getLocalizedMessage()); } // refresh will look at configuration on the server side // add additional resource with the new value // so the server side will pick it up String rsrc = "testGroupMappingRefresh_rsrc.xml"; addNewConfigResource(rsrc, userKeyGroups, "gr2", userKeyHosts, "127.0.0.1"); DFSAdmin admin = new DFSAdmin(config); String[] args = new String[] {"-refreshSuperUserGroupsConfiguration"}; // NameNode nn = cluster.getNameNode(); // Configuration conf = new Configuration(config); // conf.set(userKeyGroups, "gr2"); // superuser can proxy for this group // admin.setConf(conf); admin.run(args); try { ProxyUsers.authorize(ugi2, "127.0.0.1", config); fail("second auth for " + ugi2.getShortUserName() + " should've failed "); } catch (AuthorizationException e) { // expected System.err.println("auth for " + ugi2.getUserName() + " failed"); } try { ProxyUsers.authorize(ugi1, "127.0.0.1", config); System.err.println("auth for " + ugi1.getUserName() + " succeeded"); // expected } catch (AuthorizationException e) { fail( "second auth for " + ugi1.getShortUserName() + " should've succeeded: " + e.getLocalizedMessage()); } }
public static URLConnectionClientHandler getClientConnectionHandler( DefaultClientConfig config, PropertiesConfiguration clientConfig, final String doAsUser, final UserGroupInformation ugi) { config .getProperties() .put(URLConnectionClientHandler.PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND, true); Configuration conf = new Configuration(); conf.addResource(conf.get(SSLFactory.SSL_CLIENT_CONF_KEY, "ssl-client.xml")); UserGroupInformation.setConfiguration(conf); final ConnectionConfigurator connConfigurator = newConnConfigurator(conf); String authType = "simple"; if (clientConfig != null) { authType = clientConfig.getString("atlas.http.authentication.type", "simple"); } Authenticator authenticator = new PseudoDelegationTokenAuthenticator(); if (!authType.equals("simple")) { authenticator = new KerberosDelegationTokenAuthenticator(); } authenticator.setConnectionConfigurator(connConfigurator); final DelegationTokenAuthenticator finalAuthenticator = (DelegationTokenAuthenticator) authenticator; final DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token(); HttpURLConnectionFactory httpURLConnectionFactory = null; try { UserGroupInformation ugiToUse = ugi != null ? ugi : UserGroupInformation.getCurrentUser(); final UserGroupInformation actualUgi = (ugiToUse.getAuthenticationMethod() == UserGroupInformation.AuthenticationMethod.PROXY) ? ugiToUse.getRealUser() : ugiToUse; LOG.info( "Real User: {}, is from ticket cache? {}", actualUgi, actualUgi.isLoginTicketBased()); LOG.info("doAsUser: {}", doAsUser); httpURLConnectionFactory = new HttpURLConnectionFactory() { @Override public HttpURLConnection getHttpURLConnection(final URL url) throws IOException { try { return actualUgi.doAs( new PrivilegedExceptionAction<HttpURLConnection>() { @Override public HttpURLConnection run() throws Exception { try { return new DelegationTokenAuthenticatedURL( finalAuthenticator, connConfigurator) .openConnection(url, token, doAsUser); } catch (Exception e) { throw new IOException(e); } } }); } catch (Exception e) { if (e instanceof IOException) { throw (IOException) e; } else { throw new IOException(e); } } } }; } catch (IOException e) { LOG.warn("Error obtaining user", e); } return new URLConnectionClientHandler(httpURLConnectionFactory); }