Java tutorial
/* * 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.directory.fortress.realm; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.security.Principal; import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.directory.fortress.core.GlobalIds; import org.apache.directory.fortress.core.ReviewMgr; import org.apache.directory.fortress.core.ReviewMgrFactory; import org.apache.directory.fortress.core.AccessMgr; import org.apache.directory.fortress.core.AccessMgrFactory; import org.apache.directory.fortress.core.SecurityException; import org.apache.directory.fortress.core.GlobalErrIds; import org.apache.directory.fortress.core.model.User; import org.apache.directory.fortress.core.model.Role; import org.apache.directory.fortress.core.model.Session; import org.apache.directory.fortress.core.util.VUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class contains common functions for container managed security. These APIs may be called by external programs as needed though the expected * practice for external app usage is to call Apache Fortress Core APIs, e.g. {@link org.apache.directory.fortress.core.AccessMgr} and {@link org.apache.directory.fortress.core.ReviewMgr}. * This class is NOT thread safe if contextId is set. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class J2eePolicyMgrImpl implements J2eePolicyMgr { private static final String CLS_NM = J2eePolicyMgrImpl.class.getName(); private static final Logger LOG = LoggerFactory.getLogger(CLS_NM); private AccessMgr accessMgr; private ReviewMgr reviewMgr; private static final String SESSION = "session"; private String contextId; J2eePolicyMgrImpl() { try { accessMgr = AccessMgrFactory.createInstance(); reviewMgr = ReviewMgrFactory.createInstance(); LOG.info("{} - constructed", CLS_NM); } catch (SecurityException se) { LOG.error("{} caught SecurityException={}", CLS_NM, se); } } /** * {@inheritDoc} */ @Override public boolean authenticate(String userId, String password) throws SecurityException { boolean result = false; Session session = accessMgr.authenticate(userId, password); if (session != null) { result = true; LOG.debug("{}.authenticate userId [{}], successful", CLS_NM, userId); } else { LOG.debug("{}.authenticate userId [{}], failed", CLS_NM, userId); } return result; } /** * {@inheritDoc} */ @Override public TcPrincipal createSession(String userId, String password) throws SecurityException { User user = new User(userId, new String(password)); return createSession(user); } /** * {@inheritDoc} */ public TcPrincipal createSession(String userId, String password, List<String> roles) throws SecurityException { User user = new User(userId, new String(password)); // Load the passed in role list into list of User requested roles: if (CollectionUtils.isNotEmpty(roles)) { for (String role : roles) { user.setRoleName(role); } } return createSession(user); } /** * {@inheritDoc} */ private TcPrincipal createSession(User user) throws SecurityException { Session session = accessMgr.createSession(user, false); LOG.debug("{}.createSession userId [{}], successful", CLS_NM, user.getUserId()); HashMap<String, Object> context = new HashMap<String, Object>(); context.put(SESSION, session); // now serialize the principal: String ser = serialize(session); // Store the serialized principal inside the context hashmap // which allows overriden toString to return it later, from within an application thread. // This facilitates assertion of rbac session from the tomcat realm into the web application session. context.put(TcPrincipal.SERIALIZED, ser); return new TcPrincipal(user.getUserId(), context); } /** * {@inheritDoc} */ @Override public Session createSession(User user, boolean isTrusted) throws SecurityException { LOG.debug("{}.createSession userId [{}], isTrusted [{}]", CLS_NM, user.getUserId(), isTrusted); return accessMgr.createSession(user, isTrusted); } /** * {@inheritDoc} */ @Override public boolean hasRole(Principal principal, String roleName) throws SecurityException { String fullMethodName = CLS_NM + ".hasRole"; LOG.debug("{}.hasRole userId [{}], role [{}]", CLS_NM, principal.getName(), roleName); // Fail closed boolean result = false; // Principal must contain a HashMap that contains a Fortress session object. HashMap<String, Object> context = ((TcPrincipal) principal).getContext(); VUtil.assertNotNull(context, GlobalErrIds.SESS_CTXT_NULL, fullMethodName); // This Map must contain a Fortress Session: Session session = (Session) context.get(SESSION); VUtil.assertNotNull(session, GlobalErrIds.USER_SESS_NULL, fullMethodName); Set<String> authZRoles = accessMgr.authorizedRoles(session); if ((authZRoles != null) && (authZRoles.size() > 0)) { // Does the set of authorized roles contain a name matched to the one passed in? if (authZRoles.contains(roleName)) { // Yes, we have a match. LOG.debug("{} userId [{}], role [{}], successful", fullMethodName, principal.getName(), roleName); result = true; } else { // User is not authorized in their Session.. LOG.debug("{} userId [{}], is not authorized role [{}]", fullMethodName, principal.getName(), roleName); } } else { // User does not have any authorized Roles in their Session.. LOG.info("{} userId [{}], role [{}], has no authorized roles", fullMethodName, principal.getName(), roleName); } return result; } /** * {@inheritDoc} */ @Override public Role readRole(String roleName) throws SecurityException { return reviewMgr.readRole(new Role(roleName)); } /** * {@inheritDoc} */ @Override public List<String> searchRoles(String searchString, int limit) throws SecurityException { return reviewMgr.findRoles(searchString, limit); } /** * {@inheritDoc} */ @Override public User readUser(String userId) throws SecurityException { return reviewMgr.readUser(new User(userId)); } /** * {@inheritDoc} */ @Override public List<String> searchUsers(String searchString, int limit) throws SecurityException { return reviewMgr.findUsers(new User(searchString), limit); } /** * {@inheritDoc} */ @Override public List<String> assignedUsers(String roleName, int limit) throws SecurityException { return reviewMgr.assignedUsers(new Role(roleName), limit); } /** * {@inheritDoc} */ @Override public List<String> authorizedRoles(String userId) throws SecurityException { List<String> list = null; // This will check temporal constraints on User and Roles. Session session = createSession(new User(userId), true); // Get the Set of authorized Roles. Set<String> authZRoleSet = accessMgr.authorizedRoles(session); // If User has authorized roles. if ((authZRoleSet != null) && (authZRoleSet.size() > 0)) { // Convert the Set into a List before returning: list = new ArrayList<String>(authZRoleSet); } return list; } /** * Utility to write any object into a Base64 string. Used by this class to serialize {@link TcPrincipal} object to be returned by its toString method.. */ private String serialize(Object obj) throws SecurityException { String szRetVal = null; if (obj != null) { try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream so = new ObjectOutputStream(bo); so.writeObject(obj); so.flush(); // This encoding induces a bijection between byte[] and String (unlike UTF-8) szRetVal = bo.toString("ISO-8859-1"); } catch (IOException ioe) { String error = "serialize caught IOException: " + ioe; throw new SecurityException( org.apache.directory.fortress.realm.GlobalIds.CONTEXT_SERIALIZATION_FAILED, error, ioe); } } return szRetVal; } /** * {@inheritDoc} */ public Session deserialize(String str) throws SecurityException { // deserialize the object try { // This encoding induces a bijection between byte[] and String (unlike UTF-8) byte b[] = str.getBytes("ISO-8859-1"); ByteArrayInputStream bi = new ByteArrayInputStream(b); ObjectInputStream si = new ObjectInputStream(bi); return Session.class.cast(si.readObject()); } catch (java.io.UnsupportedEncodingException e) { throw new SecurityException( org.apache.directory.fortress.realm.GlobalIds.CONTEXT_DESERIALIZATION_FAILED_UNSUPPORTED_ENCODING, "deserialize caught UnsupportedEncodingException:" + e, e); } catch (IOException e) { LOG.warn("deserialize caught IOException:" + e); throw new SecurityException( org.apache.directory.fortress.realm.GlobalIds.CONTEXT_DESERIALIZATION_FAILED_IO, "deserialize caught IOException:" + e, e); } catch (ClassNotFoundException e) { LOG.warn("deserialize caught ClassNotFoundException:" + e); throw new SecurityException( org.apache.directory.fortress.realm.GlobalIds.CONTEXT_DESERIALIZATION_FAILED_CLASS_NOT_FOUND, "deserialize caught ClassNotFoundException:" + e, e); } } /** * {@inheritDoc} */ @Override public final void setContextId(String contextId) { this.contextId = contextId; accessMgr.setContextId(contextId); reviewMgr.setContextId(contextId); } }