You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/01 13:17:04 UTC
[06/64] [partial] knox git commit: KNOX-998 - Refactoring save 1
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
deleted file mode 100644
index b625f34..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/filter/ShiroSubjectIdentityAdapter.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * 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.hadoop.gateway.filter;
-
-import java.io.IOException;
-import java.security.Principal;
-import java.security.PrivilegedExceptionAction;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.hadoop.gateway.audit.api.Action;
-import org.apache.hadoop.gateway.audit.api.ActionOutcome;
-import org.apache.hadoop.gateway.audit.api.AuditService;
-import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
-import org.apache.hadoop.gateway.audit.api.Auditor;
-import org.apache.hadoop.gateway.audit.api.ResourceType;
-import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
-import org.apache.hadoop.gateway.security.GroupPrincipal;
-import org.apache.hadoop.gateway.security.PrimaryPrincipal;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.subject.Subject;
-
-public class ShiroSubjectIdentityAdapter implements Filter {
-
- private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
- private static AuditService auditService = AuditServiceFactory.getAuditService();
- private static Auditor auditor = auditService.getAuditor(
- AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
- AuditConstants.KNOX_COMPONENT_NAME );
-
-
- @Override
- public void init( FilterConfig filterConfig ) throws ServletException {
- }
-
- public void destroy() {
- }
-
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
-
- Subject subject = SecurityUtils.getSubject();
-
- // trigger call to shiro authorization realm
- // we use shiro authorization realm to look up groups
- subject.hasRole("authenticatedUser");
-
- CallableChain callableChain = new CallableChain(request, response, chain);
- SecurityUtils.getSubject().execute(callableChain);
- }
-
- private static class CallableChain implements Callable<Void> {
- private FilterChain chain = null;
- ServletRequest request = null;
- ServletResponse response = null;
-
- CallableChain(ServletRequest request, ServletResponse response, FilterChain chain) {
- this.request = request;
- this.response = response;
- this.chain = chain;
- }
-
- @Override
- public Void call() throws Exception {
- PrivilegedExceptionAction<Void> action = new PrivilegedExceptionAction<Void>() {
- @Override
- public Void run() throws Exception {
- chain.doFilter( request, response );
- return null;
- }
- };
- Subject shiroSubject = SecurityUtils.getSubject();
-
- if (shiroSubject == null || shiroSubject.getPrincipal() == null) {
- throw new IllegalStateException("Unable to determine authenticated user from Shiro, please check that your Knox Shiro configuration is correct");
- }
-
- final String principal = (String) shiroSubject.getPrincipal().toString();
- HashSet emptySet = new HashSet();
- Set<Principal> principals = new HashSet<>();
- Principal p = new PrimaryPrincipal(principal);
- principals.add(p);
- auditService.getContext().setUsername( principal ); //KM: Audit Fix
- String sourceUri = (String)request.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
- auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS );
-
- Set<String> userGroups = null;
- // map ldap groups saved in session to Java Subject GroupPrincipal(s)
- if (SecurityUtils.getSubject().getSession().getAttribute(SUBJECT_USER_GROUPS) != null) {
- userGroups = (Set<String>)SecurityUtils.getSubject().getSession().getAttribute(SUBJECT_USER_GROUPS);
- } else { // KnoxLdapRealm case
- if( shiroSubject.getPrincipal() instanceof String ) {
- userGroups = new HashSet<>(shiroSubject.getPrincipals().asSet());
- userGroups.remove(principal);
- } else { // KnoxPamRealm case
- Set<Principal> shiroPrincipals = new HashSet<>(shiroSubject.getPrincipals().asSet());
- userGroups = new HashSet<>(); // Here we are creating a new UserGroup
- // so we don't need to remove a Principal
- // In the case of LDAP the userGroup may have already Principal
- // added to the list of groups, so it is not needed.
- for( Principal shiroPrincipal: shiroPrincipals ) {
- userGroups.add(shiroPrincipal.toString() );
- }
- }
- }
- for (String userGroup : userGroups) {
- Principal gp = new GroupPrincipal(userGroup);
- principals.add(gp);
- }
- auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS, "Groups: " + userGroups );
-
-// The newly constructed Sets check whether this Subject has been set read-only
-// before permitting subsequent modifications. The newly created Sets also prevent
-// illegal modifications by ensuring that callers have sufficient permissions.
-//
-// To modify the Principals Set, the caller must have AuthPermission("modifyPrincipals").
-// To modify the public credential Set, the caller must have AuthPermission("modifyPublicCredentials").
-// To modify the private credential Set, the caller must have AuthPermission("modifyPrivateCredentials").
- javax.security.auth.Subject subject = new javax.security.auth.Subject(true, principals, emptySet, emptySet);
- javax.security.auth.Subject.doAs( subject, action );
-
- return null;
- }
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxCacheManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxCacheManager.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxCacheManager.java
deleted file mode 100644
index cf2d529..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxCacheManager.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.shirorealm;
-
-import org.apache.shiro.cache.ehcache.EhCacheManager;
-
-public class KnoxCacheManager extends EhCacheManager {
-
- public KnoxCacheManager() {
- setCacheManager(net.sf.ehcache.CacheManager.create());
- }
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
deleted file mode 100644
index b4d0c5c..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapContextFactory.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.hadoop.gateway.shirorealm;
-
-import java.util.Hashtable;
-
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.ldap.LdapContext;
-
-import org.apache.hadoop.gateway.GatewayMessages;
-import org.apache.hadoop.gateway.GatewayServer;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.GatewayServices;
-import org.apache.hadoop.gateway.services.security.AliasService;
-import org.apache.hadoop.gateway.services.security.AliasServiceException;
-import org.apache.hadoop.gateway.util.KnoxCLI;
-import org.apache.shiro.realm.ldap.JndiLdapContextFactory;
-
-/**
- * An extension of {@link JndiLdapContextFactory} that allows a different authentication mechanism
- * for system-level authentications (as used by authorization lookups, for example)
- * compared to regular authentication.
- *
- * <p>
- * See {@link IsisLdapRealm} for typical configuration within <tt>shiro.ini</tt>.
- */
-public class KnoxLdapContextFactory extends JndiLdapContextFactory {
-
- private static GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
-
- private String systemAuthenticationMechanism = "simple";
- private String clusterName = "";
-
- public KnoxLdapContextFactory() {
- setAuthenticationMechanism("simple");
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- @Override
- protected LdapContext createLdapContext(Hashtable env) throws NamingException {
- if(getSystemUsername() != null && getSystemUsername().equals(env.get(Context.SECURITY_PRINCIPAL))) {
- env.put(Context.SECURITY_AUTHENTICATION, getSystemAuthenticationMechanism());
- }
- return super.createLdapContext(env);
- }
-
- public String getSystemAuthenticationMechanism() {
- return systemAuthenticationMechanism != null? systemAuthenticationMechanism: getAuthenticationMechanism();
- }
-
- public void setSystemAuthenticationMechanism(String systemAuthenticationMechanism) {
- this.systemAuthenticationMechanism = systemAuthenticationMechanism;
- }
-
- @Override
- public void setSystemPassword(String systemPass) {
-
- if ( systemPass == null ) {
- return;
- }
-
- systemPass = systemPass.trim();
- if (systemPass.length() == 0) {
- return;
- }
-
- if (!systemPass.startsWith("S{ALIAS=")) {
- super.setSystemPassword( systemPass );
- return;
- }
-
- systemPass= systemPass.substring( "S{ALIAS=".length(), systemPass.length() - 1 );
- String aliasName = systemPass;
-
- GatewayServices services = GatewayServer.getGatewayServices();
- AliasService aliasService = (AliasService)services.getService(GatewayServices.ALIAS_SERVICE);
-
- String clusterName = getClusterName();
- //System.err.println("FACTORY systempass 30: " + systemPass);
- //System.err.println("FACTORY clustername 40: " + clusterName);
- //System.err.println("FACTORY SystemProperty GatewayHome 50: " + System.getProperty(GatewayConfig.GATEWAY_HOME_VAR));
- char[] password = null;
- try {
- password = aliasService.getPasswordFromAliasForCluster(clusterName, systemPass);
- } catch (AliasServiceException e) {
- LOG.unableToGetPassword(e);
- }
- //System.err.println("FACTORY password: " + ((password == null) ? "NULL" : new String(password)));
- if ( password != null ) {
- //System.err.println("FACTORY SUCCESS 20 system password :" + new String(password));
- super.setSystemPassword( new String(password) );
- } else {
- //System.err.println("FACTORY FORCING system password to blank");
- super.setSystemPassword("" );
- LOG.aliasValueNotFound(clusterName, aliasName);
- }
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- if (clusterName != null) {
- this.clusterName = clusterName.trim();
- }
- }
-
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
deleted file mode 100644
index c81125a..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * 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.hadoop.gateway.shirorealm;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.naming.AuthenticationException;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.PartialResultException;
-import javax.naming.SizeLimitExceededException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.SearchControls;
-import javax.naming.directory.SearchResult;
-import javax.naming.ldap.Control;
-import javax.naming.ldap.LdapContext;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.PagedResultsControl;
-import javax.naming.ldap.PagedResultsResponseControl;
-
-import org.apache.hadoop.gateway.GatewayMessages;
-import org.apache.hadoop.gateway.audit.api.Action;
-import org.apache.hadoop.gateway.audit.api.ActionOutcome;
-import org.apache.hadoop.gateway.audit.api.AuditService;
-import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
-import org.apache.hadoop.gateway.audit.api.Auditor;
-import org.apache.hadoop.gateway.audit.api.ResourceType;
-import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.shirorealm.impl.i18n.KnoxShiroMessages;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
-import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
-import org.apache.shiro.crypto.hash.DefaultHashService;
-import org.apache.shiro.crypto.hash.Hash;
-import org.apache.shiro.crypto.hash.HashRequest;
-import org.apache.shiro.crypto.hash.HashService;
-import org.apache.shiro.realm.ldap.JndiLdapRealm;
-import org.apache.shiro.realm.ldap.LdapContextFactory;
-import org.apache.shiro.realm.ldap.LdapUtils;
-import org.apache.shiro.subject.MutablePrincipalCollection;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.apache.shiro.util.StringUtils;
-
-/**
- * Implementation of {@link org.apache.shiro.realm.ldap.JndiLdapRealm} that also
- * returns each user's groups.
- * This implementation is heavily based on org.apache.isis.security.shiro.IsisLdapRealm.
- *
- * This implementation saves looked up ldap groups in Shiro Session to make them
- * easy to be looked up outside of this object
- *
- * <p>
- * Sample config for <tt>shiro.ini</tt>:
- *
- * [main]
- * ldapRealm=org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm
- * ldapGroupContextFactory=org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory
- * ldapRealm.contextFactory=$ldapGroupContextFactory
- * ldapRealm.contextFactory.authenticationMechanism=simple
- * ldapRealm.contextFactory.url=ldap://localhost:33389
- * ldapRealm.userDnTemplate=uid={0},ou=people,dc=hadoop,dc=apache,dc=org
- * ldapRealm.authorizationEnabled=true
- * ldapRealm.contextFactory.systemAuthenticationMechanism=simple
- * ldapRealm.searchBase=ou=groups,dc=hadoop,dc=apache,dc=org
- * ldapRealm.groupObjectClass=groupofnames
- * ldapRealm.memberAttribute=member
- * ldapRealm.memberAttributeValueTemplate=cn={0},ou=people,dc=hadoop,dc=apache,dc=org
- * ldapRealm.contextFactory.systemUsername=uid=guest,ou=people,dc=hadoop,dc=apache,dc=org
- * ldapRealm.contextFactory.clusterName=sandbox
- * ldapRealm.contextFactory.systemPassword=S{ALIAS=ldcSystemPassword}
- * [urls]
- * **=authcBasic
- *
- * # optional mapping from physical groups to logical application roles
- * ldapRealm.rolesByGroup = \
- * LDN_USERS: user_role,\
- * NYK_USERS: user_role,\
- * HKG_USERS: user_role,\
- * GLOBAL_ADMIN: admin_role,\
- * DEMOS: self-install_role
- *
- * ldapRealm.permissionsByRole=\
- * user_role = *:ToDoItemsJdo:*:*,\
- * *:ToDoItem:*:*; \
- * self-install_role = *:ToDoItemsFixturesService:install:* ; \
- * admin_role = *
- *
- * securityManager.realms = $ldapRealm
- *
- * </pre>
- */
-public class KnoxLdapRealm extends JndiLdapRealm {
-
- private static GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
- KnoxShiroMessages ShiroLog = MessagesFactory.get( KnoxShiroMessages.class );
- private static AuditService auditService = AuditServiceFactory.getAuditService();
- private static Auditor auditor = auditService.getAuditor(
- AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
- AuditConstants.KNOX_COMPONENT_NAME );
-
- private static Pattern TEMPLATE_PATTERN = Pattern.compile( "\\{(\\d+?)\\}" );
- private static String DEFAULT_PRINCIPAL_REGEX = "(.*)";
- private static final String MEMBER_SUBSTITUTION_TOKEN = "{0}";
-
- private static final SearchControls SUBTREE_SCOPE = new SearchControls();
- private static final SearchControls ONELEVEL_SCOPE = new SearchControls();
- private static final SearchControls OBJECT_SCOPE = new SearchControls();
-
- private static final String SUBJECT_USER_ROLES = "subject.userRoles";
- private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
-
- private static final String MEMBER_URL = "memberUrl";
-
- private static final String POSIX_GROUP = "posixGroup";
-
- private static final String HASHING_ALGORITHM = "SHA-256";
-
- static {
- SUBTREE_SCOPE.setSearchScope(SearchControls.SUBTREE_SCOPE);
- ONELEVEL_SCOPE.setSearchScope(SearchControls.ONELEVEL_SCOPE);
- OBJECT_SCOPE.setSearchScope( SearchControls.OBJECT_SCOPE );
- }
-
-
- private String searchBase;
- private String userSearchBase;
- private String principalRegex = DEFAULT_PRINCIPAL_REGEX;
- private Pattern principalPattern = Pattern.compile( DEFAULT_PRINCIPAL_REGEX );
- private String userDnTemplate = "{0}";
- private String userSearchFilter = null;
- private String userSearchAttributeTemplate = "{0}";
- private String userSearchScope = "subtree";
-
- private String groupSearchBase;
-
- private String groupObjectClass = "groupOfNames";
-
- // typical value: member, uniqueMember, meberUrl
- private String memberAttribute = "member";
-
- private String groupIdAttribute = "cn";
-
- private String memberAttributeValuePrefix = "uid={0}";
- private String memberAttributeValueSuffix = "";
-
- private final Map<String,String> rolesByGroup = new LinkedHashMap<String, String>();
- private final Map<String,List<String>> permissionsByRole = new LinkedHashMap<String, List<String>>();
-
- private boolean authorizationEnabled;
-
- private String userSearchAttributeName;
- private String userObjectClass = "person";
-
- private HashService hashService = new DefaultHashService();
-
- public KnoxLdapRealm() {
- HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(HASHING_ALGORITHM);
- setCredentialsMatcher(credentialsMatcher);
- }
-
- @Override
- //KNOX-534 overriding this method to be able to audit authentication exceptions
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws org.apache.shiro.authc.AuthenticationException {
- try {
- return super.doGetAuthenticationInfo(token);
- } catch ( org.apache.shiro.authc.AuthenticationException e ) {
- auditor.audit( Action.AUTHENTICATION , token.getPrincipal().toString(), ResourceType.PRINCIPAL, ActionOutcome.FAILURE, e.getMessage() );
- ShiroLog.failedLoginInfo(token);
- ShiroLog.failedLoginStackTrace(e);
- ShiroLog.failedLoginAttempt(e.getCause());
-
- throw e;
- }
- }
-
- /**
- * Get groups from LDAP.
- *
- * @param principals
- * the principals of the Subject whose AuthenticationInfo should
- * be queried from the LDAP server.
- * @param ldapContextFactory
- * factory used to retrieve LDAP connections.
- * @return an {@link AuthorizationInfo} instance containing information
- * retrieved from the LDAP server.
- * @throws NamingException
- * if any LDAP errors occur during the search.
- */
- @Override
- protected AuthorizationInfo queryForAuthorizationInfo(final PrincipalCollection principals,
- final LdapContextFactory ldapContextFactory) throws NamingException {
- if (!isAuthorizationEnabled()) {
- return null;
- }
- final Set<String> roleNames = getRoles(principals, ldapContextFactory);
- SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roleNames);
- Set<String> stringPermissions = permsFor(roleNames);
- simpleAuthorizationInfo.setStringPermissions(stringPermissions);
- return simpleAuthorizationInfo;
- }
-
- private Set<String> getRoles(PrincipalCollection principals,
- final LdapContextFactory ldapContextFactory) throws NamingException {
- final String username = (String) getAvailablePrincipal(principals);
-
- LdapContext systemLdapCtx = null;
- try {
- systemLdapCtx = ldapContextFactory.getSystemLdapContext();
- return rolesFor(principals, username, systemLdapCtx, ldapContextFactory);
- } catch (AuthenticationException e) {
- LOG.failedToGetSystemLdapConnection(e);
- return Collections.emptySet();
- } finally {
- LdapUtils.closeContext(systemLdapCtx);
- }
- }
-
- private Set<String> rolesFor(PrincipalCollection principals, final String userName, final LdapContext ldapCtx,
- final LdapContextFactory ldapContextFactory) throws NamingException {
- final Set<String> roleNames = new HashSet<>();
- final Set<String> groupNames = new HashSet<>();
-
- String userDn;
- if (userSearchAttributeName == null || userSearchAttributeName.isEmpty()) {
- // memberAttributeValuePrefix and memberAttributeValueSuffix were computed from memberAttributeValueTemplate
- userDn = memberAttributeValuePrefix + userName + memberAttributeValueSuffix;
- } else {
- userDn = getUserDn(userName);
- }
-
- // Activate paged results
- int pageSize = 100;
- int numResults = 0;
- byte[] cookie = null;
- try {
- ldapCtx.addToEnvironment(Context.REFERRAL, "ignore");
-
- ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)});
-
- do {
- // ldapsearch -h localhost -p 33389 -D uid=guest,ou=people,dc=hadoop,dc=apache,dc=org -w guest-password
- // -b dc=hadoop,dc=apache,dc=org -s sub '(objectclass=*)'
-
- NamingEnumeration<SearchResult> searchResultEnum = null;
- try {
- searchResultEnum = ldapCtx.search(
- getGroupSearchBase(),
- "objectClass=" + groupObjectClass,
- SUBTREE_SCOPE);
-
- while (searchResultEnum != null && searchResultEnum.hasMore()) { // searchResults contains all the groups in search scope
- numResults++;
- final SearchResult group = searchResultEnum.next();
- addRoleIfMember(userDn, group, roleNames, groupNames, ldapContextFactory);
- }
- } catch (PartialResultException e) {
- LOG.ignoringPartialResultException();
- } finally {
- if (searchResultEnum != null) {
- searchResultEnum.close();
- }
- }
-
- // Examine the paged results control response
- Control[] controls = ldapCtx.getResponseControls();
- if (controls != null) {
- for (Control control : controls) {
- if (control instanceof PagedResultsResponseControl) {
- PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
- cookie = prrc.getCookie();
- }
- }
- }
-
- // Re-activate paged results
- ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)});
- } while (cookie != null);
- } catch (SizeLimitExceededException e) {
- LOG.sizeLimitExceededOnlyRetrieved(numResults);
-// System.out.println("Only retrieved first " + numResults + " groups due to SizeLimitExceededException.");
- } catch(IOException e) {
- LOG.unableToSetupPagedResults();
-// System.out.println("Unabled to setup paged results");
- }
-
- // save role names and group names in session so that they can be easily looked up outside of this object
- SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_ROLES, roleNames);
- SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_GROUPS, groupNames);
- if (!groupNames.isEmpty() && (principals instanceof MutablePrincipalCollection)) {
- ((MutablePrincipalCollection)principals).addAll(groupNames, getName());
- }
- LOG.lookedUpUserRoles(roleNames, userName);
-
- return roleNames;
- }
-
- private void addRoleIfMember(final String userDn, final SearchResult group,
- final Set<String> roleNames, final Set<String> groupNames,
- final LdapContextFactory ldapContextFactory) throws NamingException {
-
- NamingEnumeration<? extends Attribute> attributeEnum = null;
- NamingEnumeration<?> e = null;
- try {
- LdapName userLdapDn = new LdapName(userDn);
- Attribute attribute = group.getAttributes().get(getGroupIdAttribute());
- String groupName = attribute.get().toString();
-
- attributeEnum = group
- .getAttributes().getAll();
- while (attributeEnum.hasMore()) {
- final Attribute attr = attributeEnum.next();
- if (!memberAttribute.equalsIgnoreCase(attr.getID())) {
- continue;
- }
- e = attr.getAll();
- while (e.hasMore()) {
- String attrValue = e.next().toString();
- if (memberAttribute.equalsIgnoreCase(MEMBER_URL)) {
- boolean dynamicGroupMember = isUserMemberOfDynamicGroup(userLdapDn,
- attrValue, // memberUrl value
- ldapContextFactory);
- if (dynamicGroupMember) {
- groupNames.add(groupName);
- String roleName = roleNameFor(groupName);
- if (roleName != null) {
- roleNames.add(roleName);
- } else {
- roleNames.add(groupName);
- }
- }
- } else {
- if (groupObjectClass.equalsIgnoreCase(POSIX_GROUP)){
- attrValue = memberAttributeValuePrefix + attrValue + memberAttributeValueSuffix;
- }
- if (userLdapDn.equals(new LdapName(attrValue))) {
- groupNames.add(groupName);
- String roleName = roleNameFor(groupName);
- if (roleName != null) {
- roleNames.add(roleName);
- } else {
- roleNames.add(groupName);
- }
- break;
- }
- }
- }
- }
- }
- finally {
- try {
- if (attributeEnum != null) {
- attributeEnum.close();
- }
- }
- finally {
- if (e != null) {
- e.close();
- }
- }
- }
- }
-
- private String roleNameFor(String groupName) {
- return !rolesByGroup.isEmpty() ? rolesByGroup.get(groupName) : groupName;
- }
-
-
- private Set<String> permsFor(Set<String> roleNames) {
- Set<String> perms = new LinkedHashSet<String>(); // preserve order
- for(String role: roleNames) {
- List<String> permsForRole = permissionsByRole.get(role);
- if(permsForRole != null) {
- perms.addAll(permsForRole);
- }
- }
- return perms;
- }
-
- public String getSearchBase() {
- return searchBase;
- }
-
- public void setSearchBase(String searchBase) {
- this.searchBase = searchBase;
- }
-
- public String getUserSearchBase() {
- return (userSearchBase != null && !userSearchBase.isEmpty()) ?
- userSearchBase : searchBase;
- }
-
- public void setUserSearchBase(String userSearchBase) {
- this.userSearchBase = userSearchBase;
- }
-
- public String getGroupSearchBase() {
- return (groupSearchBase != null && !groupSearchBase.isEmpty()) ?
- groupSearchBase : searchBase;
- }
-
- public void setGroupSearchBase(String groupSearchBase) {
- this.groupSearchBase = groupSearchBase;
- }
-
- public String getGroupObjectClass() {
- return groupObjectClass;
- }
-
- public void setGroupObjectClass(String groupObjectClassAttribute) {
- this.groupObjectClass = groupObjectClassAttribute;
- }
-
- public String getMemberAttribute() {
- return memberAttribute;
- }
-
- public void setMemberAttribute(String memberAttribute) {
- this.memberAttribute = memberAttribute;
- }
-
- public String getGroupIdAttribute() {
- return groupIdAttribute;
- }
-
- public void setGroupIdAttribute(String groupIdAttribute) {
- this.groupIdAttribute = groupIdAttribute;
- }
-
- public void setMemberAttributeValueTemplate(String template) {
- if (!StringUtils.hasText(template)) {
- String msg = "User DN template cannot be null or empty.";
- throw new IllegalArgumentException(msg);
- }
- int index = template.indexOf(MEMBER_SUBSTITUTION_TOKEN);
- if (index < 0) {
- String msg = "Member attribute value template must contain the '" +
- MEMBER_SUBSTITUTION_TOKEN + "' replacement token to understand how to " +
- "parse the group members.";
- throw new IllegalArgumentException(msg);
- }
- String prefix = template.substring(0, index);
- String suffix = template.substring(prefix.length() + MEMBER_SUBSTITUTION_TOKEN.length());
- this.memberAttributeValuePrefix = prefix;
- this.memberAttributeValueSuffix = suffix;
- }
-
- public void setRolesByGroup(Map<String, String> rolesByGroup) {
- this.rolesByGroup.putAll(rolesByGroup);
- }
-
- public void setPermissionsByRole(String permissionsByRoleStr) {
- permissionsByRole.putAll(parsePermissionByRoleString(permissionsByRoleStr));
- }
-
- public boolean isAuthorizationEnabled() {
- return authorizationEnabled;
- }
-
- public void setAuthorizationEnabled(boolean authorizationEnabled) {
- this.authorizationEnabled = authorizationEnabled;
- }
-
- public String getUserSearchAttributeName() {
- return userSearchAttributeName;
- }
-
- public void setUserSearchAttributeName(String userSearchAttributeName) {
- if (userSearchAttributeName != null) {
- userSearchAttributeName = userSearchAttributeName.trim();
- }
- this.userSearchAttributeName = userSearchAttributeName;
- }
-
- public String getUserObjectClass() {
- return userObjectClass;
- }
-
- public void setUserObjectClass(String userObjectClass) {
- this.userObjectClass = userObjectClass;
- }
-
- private Map<String, List<String>> parsePermissionByRoleString(String permissionsByRoleStr) {
- Map<String,List<String>> perms = new HashMap<>();
-
- // split by semicolon ; then by eq = then by comma ,
- StringTokenizer stSem = new StringTokenizer(permissionsByRoleStr, ";");
- while (stSem.hasMoreTokens()) {
- String roleAndPerm = stSem.nextToken();
- StringTokenizer stEq = new StringTokenizer(roleAndPerm, "=");
- if (stEq.countTokens() != 2) {
- continue;
- }
- String role = stEq.nextToken().trim();
- String perm = stEq.nextToken().trim();
- StringTokenizer stCom = new StringTokenizer(perm, ",");
- List<String> permList = new ArrayList<String>();
- while (stCom.hasMoreTokens()) {
- permList.add(stCom.nextToken().trim());
- }
- perms.put(role, permList);
- }
- return perms;
- }
-
- boolean isUserMemberOfDynamicGroup(LdapName userLdapDn, String memberUrl,
- final LdapContextFactory ldapContextFactory) throws NamingException {
-
- // ldap://host:port/dn?attributes?scope?filter?extensions
-
- boolean member = false;
-
- if (memberUrl == null) {
- return false;
- }
- String[] tokens = memberUrl.split("\\?");
- if (tokens.length < 4) {
- return false;
- }
-
- String searchBaseString = tokens[0]
- .substring(tokens[0].lastIndexOf("/") + 1);
- String searchScope = tokens[2];
- String searchFilter = tokens[3];
-
- LdapName searchBaseDn = new LdapName(searchBaseString);
-
- // do scope test
- if (searchScope.equalsIgnoreCase("base")) {
- return false;
- }
- if (!userLdapDn.toString().endsWith(searchBaseDn.toString())) {
- return false;
- }
- if (searchScope.equalsIgnoreCase("one")
- && (userLdapDn.size() != searchBaseDn.size() - 1)) {
- return false;
- }
- // search for the filter, substituting base with userDn
- // search for base_dn=userDn, scope=base, filter=filter
- LdapContext systemLdapCtx = null;
- systemLdapCtx = ldapContextFactory.getSystemLdapContext();
- NamingEnumeration<SearchResult> searchResultEnum = null;
- try {
- searchResultEnum = systemLdapCtx
- .search(userLdapDn, searchFilter,
- searchScope.equalsIgnoreCase("sub") ? SUBTREE_SCOPE
- : ONELEVEL_SCOPE);
- if (searchResultEnum.hasMore()) {
- return true;
- }
- }
- finally {
- try {
- if (searchResultEnum != null) {
- searchResultEnum.close();
- }
- }
- finally {
- LdapUtils.closeContext(systemLdapCtx);
- }
- }
- return member;
- }
-
- public String getPrincipalRegex() {
- return principalRegex;
- }
-
- public void setPrincipalRegex( String regex ) {
- if( regex == null || regex.trim().isEmpty() ) {
- principalPattern = Pattern.compile( DEFAULT_PRINCIPAL_REGEX );
- principalRegex = DEFAULT_PRINCIPAL_REGEX;
- } else {
- regex = regex.trim();
- Pattern pattern = Pattern.compile( regex );
- principalPattern = pattern;
- principalRegex = regex;
- }
- }
-
- public String getUserSearchAttributeTemplate() {
- return userSearchAttributeTemplate;
- }
-
- public void setUserSearchAttributeTemplate( final String template ) {
- this.userSearchAttributeTemplate = ( template == null ? null : template.trim() );
- }
-
- public String getUserSearchFilter() {
- return userSearchFilter;
- }
-
- public void setUserSearchFilter( final String filter ) {
- this.userSearchFilter = ( filter == null ? null : filter.trim() );
- }
-
- public String getUserSearchScope() {
- return userSearchScope;
- }
-
- public void setUserSearchScope( final String scope ) {
- this.userSearchScope = ( scope == null ? null : scope.trim().toLowerCase() );
- }
-
- private SearchControls getUserSearchControls() {
- SearchControls searchControls = SUBTREE_SCOPE;
- if ( "onelevel".equalsIgnoreCase( userSearchScope ) ) {
- searchControls = ONELEVEL_SCOPE;
- } else if ( "object".equalsIgnoreCase( userSearchScope ) ) {
- searchControls = OBJECT_SCOPE;
- }
- return searchControls;
- }
-
- @Override
- public void setUserDnTemplate( final String template ) throws IllegalArgumentException {
- userDnTemplate = template;
- }
-
- private Matcher matchPrincipal( final String principal ) {
- Matcher matchedPrincipal = principalPattern.matcher( principal );
- if( !matchedPrincipal.matches() ) {
- throw new IllegalArgumentException( "Principal " + principal + " does not match " + principalRegex );
- }
- return matchedPrincipal;
- }
-
- /**
- * Returns the LDAP User Distinguished Name (DN) to use when acquiring an
- * {@link javax.naming.ldap.LdapContext LdapContext} from the {@link LdapContextFactory}.
- * <p/>
- * If the the {@link #getUserDnTemplate() userDnTemplate} property has been set, this implementation will construct
- * the User DN by substituting the specified {@code principal} into the configured template. If the
- * {@link #getUserDnTemplate() userDnTemplate} has not been set, the method argument will be returned directly
- * (indicating that the submitted authentication token principal <em>is</em> the User DN).
- *
- * @param principal the principal to substitute into the configured {@link #getUserDnTemplate() userDnTemplate}.
- * @return the constructed User DN to use at runtime when acquiring an {@link javax.naming.ldap.LdapContext}.
- * @throws IllegalArgumentException if the method argument is null or empty
- * @throws IllegalStateException if the {@link #getUserDnTemplate userDnTemplate} has not been set.
- * @see LdapContextFactory#getLdapContext(Object, Object)
- */
- @Override
- protected String getUserDn( final String principal ) throws IllegalArgumentException, IllegalStateException {
- String userDn;
- Matcher matchedPrincipal = matchPrincipal( principal );
- String userSearchBase = getUserSearchBase();
- String userSearchAttributeName = getUserSearchAttributeName();
-
- // If not searching use the userDnTemplate and return.
- if ( ( userSearchBase == null || userSearchBase.isEmpty() ) ||
- ( userSearchAttributeName == null &&
- userSearchFilter == null &&
- !"object".equalsIgnoreCase( userSearchScope ) ) ) {
- userDn = expandTemplate( userDnTemplate, matchedPrincipal );
- LOG.computedUserDn( userDn, principal );
- return userDn;
- }
-
- // Create the searchBase and searchFilter from config.
- String searchBase = expandTemplate( getUserSearchBase(), matchedPrincipal );
- String searchFilter = null;
- if ( userSearchFilter == null ) {
- if ( userSearchAttributeName == null ) {
- searchFilter = String.format( "(objectclass=%1$s)", getUserObjectClass() );
- } else {
- searchFilter = String.format(
- "(&(objectclass=%1$s)(%2$s=%3$s))",
- getUserObjectClass(),
- userSearchAttributeName,
- expandTemplate( getUserSearchAttributeTemplate(), matchedPrincipal ) );
- }
- } else {
- searchFilter = expandTemplate( userSearchFilter, matchedPrincipal );
- }
- SearchControls searchControls = getUserSearchControls();
-
- // Search for userDn and return.
- LdapContext systemLdapCtx = null;
- NamingEnumeration<SearchResult> searchResultEnum = null;
- try {
- systemLdapCtx = getContextFactory().getSystemLdapContext();
- LOG.searchBaseFilterScope(searchBase, searchFilter, userSearchScope);
- searchResultEnum = systemLdapCtx.search( searchBase, searchFilter, searchControls );
- // SearchResults contains all the entries in search scope
- if (searchResultEnum.hasMore()) {
- SearchResult searchResult = searchResultEnum.next();
- userDn = searchResult.getNameInNamespace();
- LOG.searchedAndFoundUserDn(userDn, principal);
- return userDn;
- } else {
- throw new IllegalArgumentException("Illegal principal name: " + principal);
- }
- } catch (AuthenticationException e) {
- LOG.failedToGetSystemLdapConnection(e);
- throw new IllegalArgumentException("Illegal principal name: " + principal);
- } catch (NamingException e) {
- throw new IllegalArgumentException("Hit NamingException: " + e.getMessage());
- } finally {
- try {
- if (searchResultEnum != null) {
- searchResultEnum.close();
- }
- } catch (NamingException e) {
- // Ignore exception on close.
- }
- finally {
- LdapUtils.closeContext(systemLdapCtx);
- }
- }
- }
-
- @Override
- protected AuthenticationInfo createAuthenticationInfo(AuthenticationToken token, Object ldapPrincipal, Object ldapCredentials, LdapContext ldapContext) throws NamingException {
- HashRequest.Builder builder = new HashRequest.Builder();
- Hash credentialsHash = hashService.computeHash(builder.setSource(token.getCredentials()).setAlgorithmName(HASHING_ALGORITHM).build());
- return new SimpleAuthenticationInfo(token.getPrincipal(), credentialsHash.toHex(), credentialsHash.getSalt(), getName());
- }
-
- private static final String expandTemplate( final String template, final Matcher input ) {
- String output = template;
- Matcher matcher = TEMPLATE_PATTERN.matcher( output );
- while( matcher.find() ) {
- String lookupStr = matcher.group( 1 );
- int lookupIndex = Integer.parseInt( lookupStr );
- String lookupValue = input.group( lookupIndex );
- output = matcher.replaceFirst( lookupValue == null ? "" : lookupValue );
- matcher = TEMPLATE_PATTERN.matcher( output );
- }
- return output;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
deleted file mode 100644
index 45cdd45..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxPamRealm.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * 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.hadoop.gateway.shirorealm;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-import org.apache.hadoop.gateway.GatewayMessages;
-import org.apache.hadoop.gateway.audit.api.Action;
-import org.apache.hadoop.gateway.audit.api.ActionOutcome;
-import org.apache.hadoop.gateway.audit.api.ResourceType;
-import org.apache.hadoop.gateway.audit.api.AuditService;
-import org.apache.hadoop.gateway.audit.api.AuditServiceFactory;
-import org.apache.hadoop.gateway.audit.api.Auditor;
-import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.shirorealm.impl.i18n.KnoxShiroMessages;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationException;
-
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
-import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.authz.AuthorizationInfo;
-import org.apache.shiro.authz.SimpleAuthorizationInfo;
-import org.apache.shiro.realm.AuthorizingRealm;
-import org.apache.shiro.subject.PrincipalCollection;
-import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
-import org.apache.shiro.crypto.hash.*;
-import org.jvnet.libpam.PAM;
-import org.jvnet.libpam.PAMException;
-import org.jvnet.libpam.UnixUser;
-
-/**
- * A Unix-style
- * <a href="http://www.kernel.org/pub/linux/libs/pam/index.html">PAM</a>
- * {@link org.apache.shiro.realm.Realm Realm} that uses
- * <a href="https://github.com/kohsuke/libpam4j">libpam4j</a> to interface with
- * the PAM system libraries.
- * <p>
- * This is a single Shiro {@code Realm} that interfaces with the OS's
- * {@code PAM} subsystem which itself can be connected to several authentication
- * methods (unix-crypt,Samba, LDAP, etc.)
- * <p>
- * This {@code Realm} can also take part in Shiro's Pluggable Realms concept.
- * <p>
- * Using a {@code KnoxPamRealm} requires a PAM {@code service} name. This is the
- * name of the file under {@code /etc/pam.d} that is used to initialise and
- * configure the PAM subsytem. Normally, this file reflects the application
- * using it. For example {@code gdm}, {@code su}, etc. There is no default value
- * for this propery.
- * <p>
- * For example, defining this realm in Shiro .ini:
- *
- * <pre>
- * [main]
- * pamRealm = org.apache.shiro.realm.libpam4j.KnoxPamRealm
- * pamRealm.service = [ knox-pam-ldap-service | knox-pam-os-service | knox-pam-winbind-service ]
- * [urls]
- * **=authcBasic
- * </pre>
- *
- */
-
-public class KnoxPamRealm extends AuthorizingRealm {
- private static final String HASHING_ALGORITHM = "SHA-256";
- private static final String SUBJECT_USER_ROLES = "subject.userRoles";
- private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
- private HashService hashService = new DefaultHashService();
- KnoxShiroMessages ShiroLog = MessagesFactory.get(KnoxShiroMessages.class);
- GatewayMessages GatewayLog = MessagesFactory.get(GatewayMessages.class);
- private static AuditService auditService = AuditServiceFactory.getAuditService();
- private static Auditor auditor = auditService.getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
- AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
-
- private String service;
-
- public KnoxPamRealm() {
- HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(HASHING_ALGORITHM);
- setCredentialsMatcher(credentialsMatcher);
- }
-
- public void setService(String service) {
- this.service = service;
- }
-
- public String getService() {
- return this.service;
- }
-
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
- Set<String> roles = new LinkedHashSet<String>();
-
- UnixUserPrincipal user = principals.oneByType(UnixUserPrincipal.class);
- if (user != null) {
- roles.addAll(user.getUnixUser().getGroups());
- }
- SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_ROLES, roles);
- SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_GROUPS, roles);
-
- /* Coverity Scan CID 1361682 */
- String userName = null;
-
- if (user != null) {
- userName = user.getName();
- }
-
- GatewayLog.lookedUpUserRoles(roles, userName);
- return new SimpleAuthorizationInfo(roles);
- }
-
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- UsernamePasswordToken upToken = (UsernamePasswordToken) token;
- UnixUser user = null;
- try {
- user = (new PAM(this.getService())).authenticate(upToken.getUsername(), new String(upToken.getPassword()));
- } catch (PAMException e) {
- handleAuthFailure(token, e.getMessage(), e);
- }
- HashRequest.Builder builder = new HashRequest.Builder();
- Hash credentialsHash = hashService
- .computeHash(builder.setSource(token.getCredentials()).setAlgorithmName(HASHING_ALGORITHM).build());
- /* Coverity Scan CID 1361684 */
- if (credentialsHash == null) {
- handleAuthFailure(token, "Failed to compute hash", null);
- }
- return new SimpleAuthenticationInfo(new UnixUserPrincipal(user), credentialsHash.toHex(), credentialsHash.getSalt(),
- getName());
- }
-
- private void handleAuthFailure(AuthenticationToken token, String errorMessage, Exception e) {
- auditor.audit(Action.AUTHENTICATION, token.getPrincipal().toString(), ResourceType.PRINCIPAL, ActionOutcome.FAILURE,
- errorMessage);
- ShiroLog.failedLoginInfo(token);
-
- if (e != null) {
- ShiroLog.failedLoginAttempt(e.getCause());
- throw new AuthenticationException(e);
- }
-
- throw new AuthenticationException(errorMessage);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/UnixUserPrincipal.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/UnixUserPrincipal.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/UnixUserPrincipal.java
deleted file mode 100644
index a659888..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/UnixUserPrincipal.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.hadoop.gateway.shirorealm;
-
-import java.security.Principal;
-import org.jvnet.libpam.UnixUser;
-
-public class UnixUserPrincipal implements Principal {
- private final UnixUser userName;
-
- public UnixUserPrincipal(UnixUser userName) {
- this.userName = userName;
- }
-
- @Override
- public String getName() {
- return userName.getUserName();
- }
-
- public UnixUser getUnixUser() {
- return userName;
- }
-
- @Override
- public String toString() {
- return String.valueOf(userName.getUserName());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/impl/i18n/KnoxShiroMessages.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/impl/i18n/KnoxShiroMessages.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/impl/i18n/KnoxShiroMessages.java
deleted file mode 100644
index c9de024..0000000
--- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/impl/i18n/KnoxShiroMessages.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * 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.hadoop.gateway.shirorealm.impl.i18n;
-
-import org.apache.hadoop.gateway.i18n.messages.Message;
-import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
-import org.apache.hadoop.gateway.i18n.messages.Messages;
-
-import org.apache.hadoop.gateway.i18n.messages.StackTrace;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.subject.Subject;
-
-@Messages(logger = "org.apache.hadoop.gateway")
-public interface KnoxShiroMessages {
-
- @Message(level = MessageLevel.ERROR, text = "Shiro unable to login: {0}")
- void failedLoginAttempt(Throwable e);
-
- @Message(level = MessageLevel.INFO, text = "Could not login: {0}")
- void failedLoginInfo(AuthenticationToken token);
-
- @Message( level = MessageLevel.DEBUG, text = "Failed to Authenticate with LDAP server: {1}" )
- void failedLoginStackTrace( @StackTrace( level = MessageLevel.DEBUG ) Exception e );
-
- @Message(level = MessageLevel.INFO, text = "Successfully logged in: {0}, {1}")
- void successfulLoginAttempt(Subject subject, AuthenticationToken authToken);
-
-}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroConfig.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroConfig.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroConfig.java
new file mode 100644
index 0000000..4049a93
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroConfig.java
@@ -0,0 +1,71 @@
+/**
+ * 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.knox.gateway.deploy.impl;
+
+import org.apache.knox.gateway.topology.Provider;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class ShiroConfig {
+
+ private Map<String, Map<String, String>> sections = new LinkedHashMap<String, Map<String, String>>();
+
+ public ShiroConfig(Provider provider, String clusterName) {
+ Map<String, String> params = provider.getParams();
+ String name = null;
+ String sectionName = null;
+ String value = null;
+ for(Entry<String, String> entry : params.entrySet()) {
+ int sectionDot = entry.getKey().indexOf('.');
+ if (sectionDot > 0) {
+ sectionName = entry.getKey().substring(0, sectionDot);
+ name = entry.getKey().substring(sectionDot + 1);
+ value = entry.getValue().trim();
+ if (value.startsWith("${ALIAS=") && value.endsWith("}")) {
+ String baseName = name.substring(0, name.lastIndexOf("."));
+ addNameValueToSection(baseName + ".clusterName", clusterName, sectionName);
+ addNameValueToSection(name, "S" + value.substring(1), sectionName);
+ } else {
+ addNameValueToSection(name, value, sectionName);
+ }
+ }
+ }
+ }
+
+ private void addNameValueToSection(String name, String value, String sectionName) {
+ Map<String, String> section = sections.get(sectionName);
+ if (section == null) {
+ section = new LinkedHashMap<String, String>();
+ sections.put(sectionName, section);
+ }
+ section.put(name, value);
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for(Entry<String, Map<String, String>> section : sections.entrySet()) {
+ sb.append("[").append(section.getKey()).append("]\n");
+ for(Entry<String, String> entry : section.getValue().entrySet()) {
+ sb.append(entry.getKey()).append("=").append(entry.getValue()).append("\n");
+ }
+ }
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroDeploymentContributor.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroDeploymentContributor.java
new file mode 100644
index 0000000..111b13b
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/deploy/impl/ShiroDeploymentContributor.java
@@ -0,0 +1,140 @@
+/**
+ * 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.knox.gateway.deploy.impl;
+
+import org.apache.knox.gateway.deploy.DeploymentContext;
+import org.apache.knox.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
+import org.apache.knox.gateway.descriptor.ResourceDescriptor;
+import org.apache.knox.gateway.filter.RedirectToUrlFilter;
+import org.apache.knox.gateway.filter.ResponseCookieFilter;
+import org.apache.knox.gateway.topology.Provider;
+import org.apache.knox.gateway.topology.Service;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
+import org.jboss.shrinkwrap.descriptor.api.webcommon30.SessionConfigType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ShiroDeploymentContributor extends ProviderDeploymentContributorBase {
+
+ private static final String LISTENER_CLASSNAME = "org.apache.shiro.web.env.EnvironmentLoaderListener";
+ private static final String SHIRO_FILTER_CLASSNAME = "org.apache.shiro.web.servlet.ShiroFilter";
+ private static final String POST_FILTER_CLASSNAME = "ShiroSubjectIdentityAdapter";
+ private static final String COOKIE_FILTER_CLASSNAME = "ResponseCookieFilter";
+ private static final String REDIRECT_FILTER_CLASSNAME = "RedirectToUrlFilter";
+ private static final String SESSION_TIMEOUT = "sessionTimeout";
+ private static final String REMEMBER_ME = "rememberme";
+ private static final String SHRIO_CONFIG_FILE_NAME = "shiro.ini";
+ private static final int DEFAULT_SESSION_TIMEOUT = 30; // 30min
+
+ @Override
+ public String getRole() {
+ return "authentication";
+ }
+
+ @Override
+ public String getName() {
+ return "ShiroProvider";
+ }
+
+ @Override
+ public void contributeProvider( DeploymentContext context, Provider provider ) {
+ // Many filter based authentication mechanisms require a ServletContextListener
+ // to be added and the Knox deployment machinery provides the ability to add this
+ // through the DeploymentContext.
+
+ // Writing provider specific config out to the war for cluster specific config can be
+ // accomplished through the DeploymentContext as well. The JBoss shrinkwrap API can be
+ // used to write the asset to the war.
+
+ // add servletContextListener
+ context.getWebAppDescriptor().createListener().listenerClass( LISTENER_CLASSNAME );
+
+ // add session timeout
+ int st = DEFAULT_SESSION_TIMEOUT;
+ SessionConfigType<WebAppDescriptor> sessionConfig = context.getWebAppDescriptor().createSessionConfig();
+ Map<String, String> params = provider.getParams();
+ String sts = params.get( SESSION_TIMEOUT );
+ if( sts != null && sts.trim().length() != 0 ) {
+ st = Integer.parseInt( sts.trim() );
+ }
+ if( st <= 0 ) {
+ // user default session timeout
+ st = DEFAULT_SESSION_TIMEOUT;
+ }
+ sessionConfig.sessionTimeout( st );
+ sessionConfig.getOrCreateCookieConfig().httpOnly( true );
+ sessionConfig.getOrCreateCookieConfig().secure( true );
+
+ String clusterName = context.getTopology().getName();
+ ShiroConfig config = new ShiroConfig( provider, clusterName );
+ String configStr = config.toString();
+ if( config != null ) {
+ context.getWebArchive().addAsWebInfResource( new StringAsset( configStr ), SHRIO_CONFIG_FILE_NAME );
+ }
+ }
+
+ @Override
+ public void contributeFilter( DeploymentContext context, Provider provider,
+ Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params ) {
+ // Leveraging a third party filter is a primary usecase for Knox
+ // in order to do so, we need to make sure that the end result of the third party integration
+ // puts a standard javax.security.auth.Subject on the current thread through a doAs.
+ // As many filters do not use the standard java Subject, often times a post processing filter will
+ // need to be added in order to canonicalize the result into an expected security context.
+
+ // You may also need to do some additional processing of the response in order to not return cookies or other
+ // filter specifics that are not needed for integration with Knox. Below we do that in the pre-processing filter.
+ if (params == null) {
+ params = new ArrayList<FilterParamDescriptor>();
+ }
+ Map<String, String> providerParams = provider.getParams();
+ String redirectToUrl = providerParams.get(RedirectToUrlFilter.REDIRECT_TO_URL);
+ if (redirectToUrl != null) {
+ params.add( resource.createFilterParam()
+ .name(RedirectToUrlFilter.REDIRECT_TO_URL)
+ .value(redirectToUrl));
+ resource.addFilter().name( "Redirect" + getName() ).role(
+ getRole() ).impl( REDIRECT_FILTER_CLASSNAME ).params( params );
+ params.clear();
+ }
+
+ String cookies = providerParams.get( ResponseCookieFilter.RESTRICTED_COOKIES );
+ if (cookies == null) {
+ params.add( resource.createFilterParam()
+ .name( ResponseCookieFilter.RESTRICTED_COOKIES )
+ .value( REMEMBER_ME ) );
+ }
+ else {
+ params.add( resource.createFilterParam()
+ .name(ResponseCookieFilter.RESTRICTED_COOKIES ).value( cookies ) );
+ }
+
+ resource.addFilter().name( "Pre" + getName() ).role(
+ getRole() ).impl( COOKIE_FILTER_CLASSNAME ).params( params );
+ params.clear();
+
+ resource.addFilter().name( getName() ).role(
+ getRole() ).impl( SHIRO_FILTER_CLASSNAME ).params( params );
+ resource.addFilter().name( "Post" + getName() ).role(
+ getRole() ).impl( POST_FILTER_CLASSNAME ).params( params );
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/RedirectToUrlFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/RedirectToUrlFilter.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/RedirectToUrlFilter.java
new file mode 100644
index 0000000..2ecdd85
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/RedirectToUrlFilter.java
@@ -0,0 +1,52 @@
+/**
+ * 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.knox.gateway.filter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class RedirectToUrlFilter extends AbstractGatewayFilter {
+ public static final String REDIRECT_TO_URL = "redirectToUrl";
+
+ protected String redirectUrl = null;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ redirectUrl = filterConfig.getInitParameter(REDIRECT_TO_URL);
+ }
+
+ @Override
+ protected void doFilter( HttpServletRequest request,
+ HttpServletResponse response, FilterChain chain ) throws IOException, ServletException {
+ if (redirectUrl != null && request.getHeader("Authorization") == null) {
+ response.sendRedirect(redirectUrl + getOriginalQueryString(request));
+ }
+ chain.doFilter( request, response );
+ }
+
+ private String getOriginalQueryString(HttpServletRequest request) {
+ String originalQueryString = request.getQueryString();
+ return (originalQueryString == null) ? "" : "?" + originalQueryString;
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ResponseCookieFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ResponseCookieFilter.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ResponseCookieFilter.java
new file mode 100644
index 0000000..9ea9302
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ResponseCookieFilter.java
@@ -0,0 +1,88 @@
+/**
+ * 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.knox.gateway.filter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ResponseCookieFilter extends AbstractGatewayFilter {
+ public static final String RESTRICTED_COOKIES = "restrictedCookies";
+
+ protected static List<String> restrictedCookies = new ArrayList<String>();
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ String cookies = filterConfig.getInitParameter(RESTRICTED_COOKIES);
+ if (cookies != null) {
+ restrictedCookies = Arrays.asList(cookies.split(","));
+ }
+ }
+
+ @Override
+ protected void doFilter( HttpServletRequest request, HttpServletResponse response, FilterChain chain ) throws IOException, ServletException {
+ ResponseWrapper responseWrapper = new ResponseWrapper( response );
+ chain.doFilter( request, responseWrapper );
+ }
+
+ // inner class wraps response to prevent adding of not allowed headers
+ private static class ResponseWrapper extends HttpServletResponseWrapper {
+ public ResponseWrapper( HttpServletResponse response ) {
+ super( response );
+ }
+
+ public void addCookie( Cookie cookie ) {
+ if( cookie != null && isAllowedHeader( cookie.getName() ) ) {
+ super.addCookie( cookie );
+ }
+ }
+
+ public void setHeader( String name, String value ) {
+ if( isAllowedHeader( name ) ) {
+ super.setHeader( name, value );
+ }
+ }
+
+ public void addHeader( String name, String value ) {
+ if( isAllowedHeader( name ) ) {
+ super.addHeader( name, value );
+ }
+ }
+
+ private boolean isAllowedHeader( String value ) {
+ if( value != null ) {
+ for( String v : restrictedCookies ) {
+ if( value.contains( v ) ) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ShiroSubjectIdentityAdapter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ShiroSubjectIdentityAdapter.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ShiroSubjectIdentityAdapter.java
new file mode 100644
index 0000000..6fb1340
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/filter/ShiroSubjectIdentityAdapter.java
@@ -0,0 +1,150 @@
+/**
+ * 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.knox.gateway.filter;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.knox.gateway.audit.api.Action;
+import org.apache.knox.gateway.audit.api.ActionOutcome;
+import org.apache.knox.gateway.audit.api.AuditService;
+import org.apache.knox.gateway.audit.api.AuditServiceFactory;
+import org.apache.knox.gateway.audit.api.Auditor;
+import org.apache.knox.gateway.audit.api.ResourceType;
+import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
+import org.apache.knox.gateway.security.GroupPrincipal;
+import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+
+public class ShiroSubjectIdentityAdapter implements Filter {
+
+ private static final String SUBJECT_USER_GROUPS = "subject.userGroups";
+ private static AuditService auditService = AuditServiceFactory.getAuditService();
+ private static Auditor auditor = auditService.getAuditor(
+ AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
+ AuditConstants.KNOX_COMPONENT_NAME );
+
+
+ @Override
+ public void init( FilterConfig filterConfig ) throws ServletException {
+ }
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+
+ Subject subject = SecurityUtils.getSubject();
+
+ // trigger call to shiro authorization realm
+ // we use shiro authorization realm to look up groups
+ subject.hasRole("authenticatedUser");
+
+ CallableChain callableChain = new CallableChain(request, response, chain);
+ SecurityUtils.getSubject().execute(callableChain);
+ }
+
+ private static class CallableChain implements Callable<Void> {
+ private FilterChain chain = null;
+ ServletRequest request = null;
+ ServletResponse response = null;
+
+ CallableChain(ServletRequest request, ServletResponse response, FilterChain chain) {
+ this.request = request;
+ this.response = response;
+ this.chain = chain;
+ }
+
+ @Override
+ public Void call() throws Exception {
+ PrivilegedExceptionAction<Void> action = new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ chain.doFilter( request, response );
+ return null;
+ }
+ };
+ Subject shiroSubject = SecurityUtils.getSubject();
+
+ if (shiroSubject == null || shiroSubject.getPrincipal() == null) {
+ throw new IllegalStateException("Unable to determine authenticated user from Shiro, please check that your Knox Shiro configuration is correct");
+ }
+
+ final String principal = (String) shiroSubject.getPrincipal().toString();
+ HashSet emptySet = new HashSet();
+ Set<Principal> principals = new HashSet<>();
+ Principal p = new PrimaryPrincipal(principal);
+ principals.add(p);
+ auditService.getContext().setUsername( principal ); //KM: Audit Fix
+ String sourceUri = (String)request.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
+ auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS );
+
+ Set<String> userGroups = null;
+ // map ldap groups saved in session to Java Subject GroupPrincipal(s)
+ if (SecurityUtils.getSubject().getSession().getAttribute(SUBJECT_USER_GROUPS) != null) {
+ userGroups = (Set<String>)SecurityUtils.getSubject().getSession().getAttribute(SUBJECT_USER_GROUPS);
+ } else { // KnoxLdapRealm case
+ if( shiroSubject.getPrincipal() instanceof String ) {
+ userGroups = new HashSet<>(shiroSubject.getPrincipals().asSet());
+ userGroups.remove(principal);
+ } else { // KnoxPamRealm case
+ Set<Principal> shiroPrincipals = new HashSet<>(shiroSubject.getPrincipals().asSet());
+ userGroups = new HashSet<>(); // Here we are creating a new UserGroup
+ // so we don't need to remove a Principal
+ // In the case of LDAP the userGroup may have already Principal
+ // added to the list of groups, so it is not needed.
+ for( Principal shiroPrincipal: shiroPrincipals ) {
+ userGroups.add(shiroPrincipal.toString() );
+ }
+ }
+ }
+ for (String userGroup : userGroups) {
+ Principal gp = new GroupPrincipal(userGroup);
+ principals.add(gp);
+ }
+ auditor.audit( Action.AUTHENTICATION , sourceUri, ResourceType.URI, ActionOutcome.SUCCESS, "Groups: " + userGroups );
+
+// The newly constructed Sets check whether this Subject has been set read-only
+// before permitting subsequent modifications. The newly created Sets also prevent
+// illegal modifications by ensuring that callers have sufficient permissions.
+//
+// To modify the Principals Set, the caller must have AuthPermission("modifyPrincipals").
+// To modify the public credential Set, the caller must have AuthPermission("modifyPublicCredentials").
+// To modify the private credential Set, the caller must have AuthPermission("modifyPrivateCredentials").
+ javax.security.auth.Subject subject = new javax.security.auth.Subject(true, principals, emptySet, emptySet);
+ javax.security.auth.Subject.doAs( subject, action );
+
+ return null;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxCacheManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxCacheManager.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxCacheManager.java
new file mode 100644
index 0000000..123d16e
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxCacheManager.java
@@ -0,0 +1,27 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.shirorealm;
+
+import org.apache.shiro.cache.ehcache.EhCacheManager;
+
+public class KnoxCacheManager extends EhCacheManager {
+
+ public KnoxCacheManager() {
+ setCacheManager(net.sf.ehcache.CacheManager.create());
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/af9b0c3d/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxLdapContextFactory.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxLdapContextFactory.java b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxLdapContextFactory.java
new file mode 100644
index 0000000..aa28594
--- /dev/null
+++ b/gateway-provider-security-shiro/src/main/java/org/apache/knox/gateway/shirorealm/KnoxLdapContextFactory.java
@@ -0,0 +1,125 @@
+/*
+ * 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.knox.gateway.shirorealm;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.knox.gateway.GatewayMessages;
+import org.apache.knox.gateway.GatewayServer;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.services.security.AliasServiceException;
+import org.apache.shiro.realm.ldap.JndiLdapContextFactory;
+
+/**
+ * An extension of {@link JndiLdapContextFactory} that allows a different authentication mechanism
+ * for system-level authentications (as used by authorization lookups, for example)
+ * compared to regular authentication.
+ *
+ * <p>
+ * See {@link IsisLdapRealm} for typical configuration within <tt>shiro.ini</tt>.
+ */
+public class KnoxLdapContextFactory extends JndiLdapContextFactory {
+
+ private static GatewayMessages LOG = MessagesFactory.get( GatewayMessages.class );
+
+ private String systemAuthenticationMechanism = "simple";
+ private String clusterName = "";
+
+ public KnoxLdapContextFactory() {
+ setAuthenticationMechanism("simple");
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ protected LdapContext createLdapContext(Hashtable env) throws NamingException {
+ if(getSystemUsername() != null && getSystemUsername().equals(env.get(Context.SECURITY_PRINCIPAL))) {
+ env.put(Context.SECURITY_AUTHENTICATION, getSystemAuthenticationMechanism());
+ }
+ return super.createLdapContext(env);
+ }
+
+ public String getSystemAuthenticationMechanism() {
+ return systemAuthenticationMechanism != null? systemAuthenticationMechanism: getAuthenticationMechanism();
+ }
+
+ public void setSystemAuthenticationMechanism(String systemAuthenticationMechanism) {
+ this.systemAuthenticationMechanism = systemAuthenticationMechanism;
+ }
+
+ @Override
+ public void setSystemPassword(String systemPass) {
+
+ if ( systemPass == null ) {
+ return;
+ }
+
+ systemPass = systemPass.trim();
+ if (systemPass.length() == 0) {
+ return;
+ }
+
+ if (!systemPass.startsWith("S{ALIAS=")) {
+ super.setSystemPassword( systemPass );
+ return;
+ }
+
+ systemPass= systemPass.substring( "S{ALIAS=".length(), systemPass.length() - 1 );
+ String aliasName = systemPass;
+
+ GatewayServices services = GatewayServer.getGatewayServices();
+ AliasService aliasService = (AliasService)services.getService(GatewayServices.ALIAS_SERVICE);
+
+ String clusterName = getClusterName();
+ //System.err.println("FACTORY systempass 30: " + systemPass);
+ //System.err.println("FACTORY clustername 40: " + clusterName);
+ //System.err.println("FACTORY SystemProperty GatewayHome 50: " + System.getProperty(GatewayConfig.GATEWAY_HOME_VAR));
+ char[] password = null;
+ try {
+ password = aliasService.getPasswordFromAliasForCluster(clusterName, systemPass);
+ } catch (AliasServiceException e) {
+ LOG.unableToGetPassword(e);
+ }
+ //System.err.println("FACTORY password: " + ((password == null) ? "NULL" : new String(password)));
+ if ( password != null ) {
+ //System.err.println("FACTORY SUCCESS 20 system password :" + new String(password));
+ super.setSystemPassword( new String(password) );
+ } else {
+ //System.err.println("FACTORY FORCING system password to blank");
+ super.setSystemPassword("" );
+ LOG.aliasValueNotFound(clusterName, aliasName);
+ }
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public void setClusterName(String clusterName) {
+ if (clusterName != null) {
+ this.clusterName = clusterName.trim();
+ }
+ }
+
+}
\ No newline at end of file