ranger-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sneet...@apache.org
Subject [1/2] incubator-ranger git commit: This patch adds PAM auth support to ranger-admin, including the remote authentication.
Date Tue, 07 Jun 2016 19:38:59 GMT
Repository: incubator-ranger
Updated Branches:
  refs/heads/ranger-842-tester [created] 9ec52527c


This patch adds PAM auth support to ranger-admin, including the remote authentication.

To activate:

* set ranger.authentication.method to PAM .
* create /etc/pam.d/ranger-remote (not configurable)
* create /etc/pam.d/ranger-admin (configurable)
* set ranger.pam.service property to "ranger-admin" (standard) or the name you configured
above

Signed-off-by: sneethiraj <sneethir@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/57217d02
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/57217d02
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/57217d02

Branch: refs/heads/ranger-842-tester
Commit: 57217d02bb42bb4076a5a3a892ce22f0d91b8fd8
Parents: a01cce3
Author: Bolke de Bruin <bolke@xs4all.nl>
Authored: Sun Feb 14 00:39:07 2016 +0100
Committer: sneethiraj <sneethir@apache.org>
Committed: Tue Jun 7 15:37:10 2016 -0400

----------------------------------------------------------------------
 pom.xml                                         |   1 +
 .../handler/RangerAuthenticationProvider.java   |  61 +++++
 unixauthclient/pom.xml                          |   6 +
 .../unix/jaas/PamLoginModule.java               | 222 +++++++++++++++++++
 .../authentication/unix/jaas/PamPrincipal.java  |  86 +++++++
 .../jaas/UsernamePasswordCallbackHandler.java   |  38 ++++
 unixauthnative/pom.xml                          |   2 +-
 unixauthnative/src/main/c/credValidator.c       |  89 ++++++--
 8 files changed, 480 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index ef78fb5..8ed21b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -188,6 +188,7 @@
         <junit.version>4.12</junit.version>
         <kafka.version>0.9.0.0</kafka.version>
         <knox.gateway.version>0.6.0</knox.gateway.version>
+        <libpam4j.version>1.8</libpam4j.version>
         <local.lib.dir>${project.basedir}/../lib/local</local.lib.dir>
         <log4j.version>1.2.17</log4j.version>
         <metrics.core.version>3.0.2</metrics.core.version>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
b/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
index 8cd4bac..9525612 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
@@ -126,6 +126,12 @@ public class RangerAuthenticationProvider implements AuthenticationProvider
{
 					return authentication;
 				}
 			}
+			if (rangerAuthenticationMethod.equalsIgnoreCase("PAM")) {
+				authentication = getPamAuthentication(authentication);
+				if(authentication!=null && authentication.isAuthenticated()) {
+					return authentication;
+				}
+			}
 			String encoder="SHA256";
 			try{
 				authentication=getJDBCAuthentication(authentication,encoder);
@@ -296,6 +302,61 @@ public class RangerAuthenticationProvider implements AuthenticationProvider
{
 		return authentication;
 	}
 
+	public Authentication getPamAuthentication(Authentication authentication) {
+		try {
+			String rangerLdapDefaultRole = PropertiesUtil.getProperty(
+					"ranger.ldap.default.role", "ROLE_USER");
+			DefaultJaasAuthenticationProvider jaasAuthenticationProvider = new DefaultJaasAuthenticationProvider();
+			String loginModuleName = "org.apache.ranger.authentication.unix.jaas.PamLoginModule";
+			LoginModuleControlFlag controlFlag = LoginModuleControlFlag.REQUIRED;
+			Map<String, String> options = PropertiesUtil.getPropertiesMap();
+
+			if (!options.containsKey("ranger.pam.service"))
+				options.put("ranger.pam.service", "ranger-admin");
+
+			AppConfigurationEntry appConfigurationEntry = new AppConfigurationEntry(
+					loginModuleName, controlFlag, options);
+			AppConfigurationEntry[] appConfigurationEntries = new AppConfigurationEntry[] { appConfigurationEntry
};
+			Map<String, AppConfigurationEntry[]> appConfigurationEntriesOptions = new HashMap<String,
AppConfigurationEntry[]>();
+			appConfigurationEntriesOptions.put("SPRINGSECURITY",
+					appConfigurationEntries);
+			Configuration configuration = new InMemoryConfiguration(
+					appConfigurationEntriesOptions);
+			jaasAuthenticationProvider.setConfiguration(configuration);
+			RoleUserAuthorityGranter authorityGranter = new RoleUserAuthorityGranter();
+			RoleUserAuthorityGranter[] authorityGranters = new RoleUserAuthorityGranter[] { authorityGranter
};
+			jaasAuthenticationProvider.setAuthorityGranters(authorityGranters);
+			jaasAuthenticationProvider.afterPropertiesSet();
+			String userName = authentication.getName();
+			String userPassword = "";
+			if (authentication.getCredentials() != null) {
+				userPassword = authentication.getCredentials().toString();
+			}
+
+			// getting user authenticated
+			if (userName != null && userPassword != null
+					&& !userName.trim().isEmpty()
+					&& !userPassword.trim().isEmpty()) {
+				final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+				grantedAuths.add(new SimpleGrantedAuthority(
+						rangerLdapDefaultRole));
+				final UserDetails principal = new User(userName, userPassword,
+						grantedAuths);
+				final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(
+						principal, userPassword, grantedAuths);
+				authentication = jaasAuthenticationProvider
+						.authenticate(finalAuthentication);
+				authentication=getAuthenticationWithGrantedAuthority(authentication);
+				return authentication;
+			} else {
+				return authentication;
+			}
+		} catch (Exception e) {
+			logger.debug("Pam Authentication Failed:", e);
+		}
+		return authentication;
+	}
+
 	public Authentication getUnixAuthentication(Authentication authentication) {
 
 		try {

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthclient/pom.xml
----------------------------------------------------------------------
diff --git a/unixauthclient/pom.xml b/unixauthclient/pom.xml
index a4513e6..b748dcd 100644
--- a/unixauthclient/pom.xml
+++ b/unixauthclient/pom.xml
@@ -82,5 +82,11 @@
             <artifactId>slf4j-api</artifactId>
             <version>${slf4j-api.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.kohsuke</groupId>
+            <artifactId>libpam4j</artifactId>
+            <version>${libpam4j.version}</version>
+        </dependency>
+
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamLoginModule.java
----------------------------------------------------------------------
diff --git a/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamLoginModule.java
b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamLoginModule.java
new file mode 100644
index 0000000..d1107ef
--- /dev/null
+++ b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamLoginModule.java
@@ -0,0 +1,222 @@
+/*
+ * 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.ranger.authentication.unix.jaas;
+
+import org.jvnet.libpam.PAM;
+import org.jvnet.libpam.PAMException;
+import org.jvnet.libpam.UnixUser;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.*;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class PamLoginModule extends Object implements LoginModule
+{
+    public static final String SERVICE_KEY = "ranger.pam.service";
+
+    private PAM _pam;
+    private Subject _subject;
+    private CallbackHandler _callbackHandler;
+    private Map<String, ?> _options;
+
+    private String _username;
+    private String _password;
+
+    private boolean _authSucceeded;
+    private PamPrincipal _principal;
+
+    public PamLoginModule()
+    {
+        super();
+        _authSucceeded = false;
+    }
+
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,
?> sharedState, Map<String, ?> options)
+    {
+        _subject = subject;
+        _callbackHandler = callbackHandler;
+        _options = new HashMap<>(options);
+    }
+
+    @Override
+    public boolean login() throws LoginException
+    {
+        initializePam();
+        obtainUserAndPassword();
+        return performLogin();
+    }
+
+    private void initializePam() throws LoginException
+    {
+        String service = (String)_options.get(SERVICE_KEY);
+        if (service == null)
+        {
+            throw new LoginException("Error: PAM service was not defined");
+        }
+        createPam(service);
+    }
+
+    private void createPam(String service) throws LoginException
+    {
+        try
+        {
+            _pam = new PAM(service);
+        }
+        catch (PAMException ex)
+        {
+            LoginException le = new LoginException("Error initializing PAM");
+            le.initCause(ex);
+            throw le;
+        }
+    }
+
+    private void obtainUserAndPassword() throws LoginException
+    {
+        if (_callbackHandler == null)
+        {
+            throw new LoginException("Error: no CallbackHandler available  to gather authentication
information from the user");
+        }
+
+        try
+        {
+            NameCallback nameCallback = new NameCallback("username");
+            PasswordCallback passwordCallback = new PasswordCallback("password", false);
+
+            invokeCallbackHandler(nameCallback, passwordCallback);
+
+            initUserName(nameCallback);
+            initPassword(passwordCallback);
+        }
+        catch (IOException | UnsupportedCallbackException ex)
+        {
+            LoginException le = new LoginException("Error in callbacks");
+            le.initCause(ex);
+            throw le;
+        }
+    }
+
+    private void invokeCallbackHandler(NameCallback nameCallback, PasswordCallback passwordCallback)
throws IOException, UnsupportedCallbackException
+    {
+        Callback[] callbacks = new Callback[2];
+        callbacks[0] = nameCallback;
+        callbacks[1] = passwordCallback;
+
+        _callbackHandler.handle(callbacks);
+    }
+
+    private void initUserName(NameCallback nameCallback)
+    {
+        _username = nameCallback.getName();
+    }
+
+    private void initPassword(PasswordCallback passwordCallback)
+    {
+        char[] password = passwordCallback.getPassword();
+        _password = new String(password);
+
+        passwordCallback.clearPassword();
+    }
+
+    private boolean performLogin() throws LoginException
+    {
+        try
+        {
+            UnixUser user = _pam.authenticate(_username, _password);
+            _principal = new PamPrincipal(user);
+            _authSucceeded = true;
+
+            return true;
+        }
+        catch (PAMException ex)
+        {
+            LoginException le = new FailedLoginException("Invalid username or password");
+            le.initCause(ex);
+            throw le;
+        }
+    }
+
+    @Override
+    public boolean commit() throws LoginException
+    {
+        if (_authSucceeded == false)
+        {
+            return false;
+        }
+
+        if (_subject.isReadOnly())
+        {
+            cleanup();
+            throw new LoginException("Subject is read-only");
+        }
+
+        Set<Principal> principals = _subject.getPrincipals();
+        if (principals.contains(_principal) == false)
+        {
+            principals.add(_principal);
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean abort() throws LoginException
+    {
+        if (_authSucceeded == false)
+        {
+            return false;
+        }
+
+        cleanup();
+        return true;
+    }
+
+    @Override
+    public boolean logout() throws LoginException
+    {
+        if (_subject.isReadOnly())
+        {
+            cleanup();
+            throw new LoginException("Subject is read-only");
+        }
+
+        _subject.getPrincipals().remove(_principal);
+
+        cleanup();
+        return true;
+    }
+
+    private void cleanup()
+    {
+        _authSucceeded = false;
+        _username = null;
+        _password = null;
+        _principal = null;
+        _pam.dispose();
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamPrincipal.java
----------------------------------------------------------------------
diff --git a/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamPrincipal.java
b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamPrincipal.java
new file mode 100644
index 0000000..8379f3f
--- /dev/null
+++ b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/PamPrincipal.java
@@ -0,0 +1,86 @@
+/*
+ * 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.ranger.authentication.unix.jaas;
+
+import org.jvnet.libpam.UnixUser;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Set;
+
+
+public class PamPrincipal extends Object implements Principal {
+    private String _userName;
+    private String _gecos;
+    private String _homeDir;
+    private String _shell;
+    private int _uid;
+    private int _gid;
+    private Set<String> _groups;
+
+    public PamPrincipal(UnixUser user)
+    {
+        super();
+        _userName = user.getUserName();
+        _gecos = user.getGecos();
+        _homeDir = user.getDir();
+        _shell = user.getShell();
+        _uid = user.getUID();
+        _gid = user.getGID();
+        _groups = Collections.unmodifiableSet(user.getGroups());
+    }
+
+    @Override
+    public String getName()
+    {
+        return _userName;
+    }
+
+    public String getGecos()
+    {
+        return _gecos;
+    }
+
+    public String getHomeDir()
+    {
+        return _homeDir;
+    }
+
+    public String getShell()
+    {
+        return _shell;
+    }
+
+    public int getUid()
+    {
+        return _uid;
+    }
+
+    public int getGid()
+    {
+        return _gid;
+    }
+
+    public Set<String> getGroups()
+    {
+        return _groups;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/UsernamePasswordCallbackHandler.java
----------------------------------------------------------------------
diff --git a/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/UsernamePasswordCallbackHandler.java
b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/UsernamePasswordCallbackHandler.java
new file mode 100644
index 0000000..a73f653
--- /dev/null
+++ b/unixauthclient/src/main/java/org/apache/ranger/authentication/unix/jaas/UsernamePasswordCallbackHandler.java
@@ -0,0 +1,38 @@
+package org.apache.ranger.authentication.unix.jaas;
+
+import javax.security.auth.callback.*;
+import java.io.IOException;
+
+public class UsernamePasswordCallbackHandler extends Object implements CallbackHandler {
+    private String _user;
+    private String _password;
+
+    public UsernamePasswordCallbackHandler(String user, String password) {
+        super();
+        _user = user;
+        _password = password;
+    }
+
+    @Override
+    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
{
+        for (Callback callback : callbacks) {
+            if (callback instanceof NameCallback) {
+                handleName((NameCallback) callback);
+            } else if (callback instanceof PasswordCallback) {
+                handlePassword((PasswordCallback) callback);
+            } else {
+                throw new UnsupportedCallbackException(callback);
+            }
+        }
+    }
+
+    private void handleName(NameCallback callback) {
+        callback.setName(_user);
+    }
+
+    private void handlePassword(PasswordCallback callback) {
+        char[] passwordChars = _password.toCharArray();
+        callback.setPassword(passwordChars);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthnative/pom.xml
----------------------------------------------------------------------
diff --git a/unixauthnative/pom.xml b/unixauthnative/pom.xml
index 62aa4e2..70d1469 100644
--- a/unixauthnative/pom.xml
+++ b/unixauthnative/pom.xml
@@ -46,7 +46,7 @@
                         </source>
                     </sources>
                     <linkerEndOptions>
-                        <linkerEndOption>-lcrypt</linkerEndOption>
+                        <linkerEndOption>-lpam</linkerEndOption>
                     </linkerEndOptions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/57217d02/unixauthnative/src/main/c/credValidator.c
----------------------------------------------------------------------
diff --git a/unixauthnative/src/main/c/credValidator.c b/unixauthnative/src/main/c/credValidator.c
index d706a93..ab19080 100644
--- a/unixauthnative/src/main/c/credValidator.c
+++ b/unixauthnative/src/main/c/credValidator.c
@@ -14,50 +14,91 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+ /*
+  You need to add the following (or equivalent) to the
+  /etc/pam.d/ranger-remote file:
+  # check authorization
+  auth       required     pam_unix.so
+  account    required     pam_unix.so
+ */
+
 #include <stdio.h>
+#include <stdarg.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <pwd.h>
-#include <shadow.h>
 #include <string.h>
 #include <sys/types.h>
-#include <crypt.h>
+#include <security/pam_appl.h>
+
+int pamconv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void
*appdata_ptr) {
+  if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) {
+		fprintf(stderr, "ERROR: Unexpected PAM conversation '%d/%s'\n", msg[0]->msg_style, msg[0]->msg);
+		return PAM_CONV_ERR;
+  }
+  if (!appdata_ptr) {
+		fprintf(stderr, "ERROR: No password available to conversation!\n");
+		return PAM_CONV_ERR;
+  }
+	*resp = calloc(num_msg, sizeof(struct pam_response));
+	if (!*resp) {
+		fprintf(stderr, "ERROR: Out of memory!\n");
+		return PAM_CONV_ERR;
+  }
+  (*resp)[0].resp = strdup((char *) appdata_ptr);
+  (*resp)[0].resp_retcode = 0;
+
+	return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
+}
+
+struct pam_conv conv = { pamconv, NULL };
 
 int main(int ac, char **av, char **ev)
 {
 	char username[64] ;
 	char password[64] ;
 	char line[512] ;
-	struct passwd *pwp;
-	struct spwd *spwd ; 
 
-	fgets(line,512,stdin) ;
+	int retval;
+	pam_handle_t *pamh = NULL;
 
+	fgets(line,512,stdin) ;
 	sscanf(line, "LOGIN:%s %s",username,password) ;
+	conv.appdata_ptr = (char *) password;
 
-	pwp = getpwnam(username) ;
-
-	if (pwp == (struct passwd *)NULL) {
+	retval = pam_start("ranger-remote", username, &conv, &pamh);
+	if (retval != PAM_SUCCESS) {
+		/* why expose this? */
 		fprintf(stdout, "FAILED: [%s] does not exists.\n", username) ;
-		exit(1) ;
+		exit(1);
+	}
+
+	retval = pam_authenticate(pamh, 0);
+	if (retval != PAM_SUCCESS) {
+		fprintf(stdout, "FAILED: Password did not match.\n") ;
+		exit(1);
+	}
+
+	/* authorize */
+	retval = pam_acct_mgmt(pamh, 0);
+	if (retval != PAM_SUCCESS) {
+		fprintf(stdout, "FAILED: [%s] is not authorized.\n", username) ;
+		exit(1);
 	}
-	
-	spwd = getspnam(pwp->pw_name) ;
 
-	if (spwd == (struct spwd *)NULL) {
-		fprintf(stdout, "FAILED: unable to get (shadow) password for %s\n", username) ;
-		exit(1) ;
+	/* establish the requested credentials */
+	if ((retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
+			fprintf(stdout, "FAILED: Error setting credentials for [%s].\n", username) ;
+    		exit(1);
 	}
-	else {
-		char *gen = crypt(password,spwd->sp_pwdp) ;
-		if (strcmp(spwd->sp_pwdp,gen) == 0) {
-			fprintf(stdout, "OK:\n") ;
-			exit(0);
-		}
-		else {
-			fprintf(stdout, "FAILED: Password did not match.\n") ;
-			exit(1) ;
-		}
+
+	/* not opening a session, as logout has not been implemented as a remote service */
+	fprintf(stdout, "OK:\n") ;
+
+	if (pamh) {
+		pam_end(pamh, retval);
 	}
+
 	exit(0) ;
 }


Mime
View raw message