| /* |
| * 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.geode.internal.cache.tier.sockets; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.apache.logging.log4j.Logger; |
| import org.apache.shiro.subject.Subject; |
| |
| import org.apache.geode.annotations.VisibleForTesting; |
| import org.apache.geode.internal.security.AuthorizeRequest; |
| import org.apache.geode.internal.security.AuthorizeRequestPP; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| public class ClientUserAuths { |
| private static final Logger logger = LogService.getLogger(); |
| // private AtomicLong counter = new AtomicLong(1); |
| private Random uniqueIdGenerator = null; |
| private int m_seed; |
| private long m_firstId; |
| |
| private ConcurrentHashMap<Long, UserAuthAttributes> uniqueIdVsUserAuth = |
| new ConcurrentHashMap<Long, UserAuthAttributes>(); |
| private ConcurrentHashMap<String, UserAuthAttributes> cqNameVsUserAuth = |
| new ConcurrentHashMap<String, UserAuthAttributes>(); |
| private ConcurrentHashMap<Long, Subject> uniqueIdVsSubject = |
| new ConcurrentHashMap<Long, Subject>(); |
| |
| public long putUserAuth(UserAuthAttributes userAuthAttr) { |
| // TODO:hitesh should we do random here |
| // long newId = counter.getAndIncrement(); |
| long newId = getNextID(); |
| uniqueIdVsUserAuth.put(newId, userAuthAttr); |
| return newId; |
| } |
| |
| public long putSubject(Subject subject) { |
| long newId = getNextID(); |
| uniqueIdVsSubject.put(newId, subject); |
| logger.debug("Subject of {} added.", newId); |
| return newId; |
| } |
| |
| public ClientUserAuths(int clientProxyHashcode) { |
| m_seed = clientProxyHashcode; |
| uniqueIdGenerator = new Random(m_seed + System.currentTimeMillis()); |
| m_firstId = uniqueIdGenerator.nextLong(); |
| } |
| |
| private synchronized long getNextID() { |
| long uniqueId = uniqueIdGenerator.nextLong(); |
| if (uniqueId == m_firstId) { |
| uniqueIdGenerator = new Random(m_seed + System.currentTimeMillis()); |
| m_firstId = uniqueIdGenerator.nextLong(); |
| // now every user need to reauthenticate as we are short of Ids.. |
| // though possibility of this is rare. |
| uniqueIdVsUserAuth.clear(); |
| return m_firstId; |
| } |
| return uniqueId; |
| } |
| |
| public UserAuthAttributes getUserAuthAttributes(long userId) { |
| return uniqueIdVsUserAuth.get(userId); |
| } |
| |
| @VisibleForTesting |
| protected Collection<Subject> getSubjects() { |
| return Collections.unmodifiableCollection(this.uniqueIdVsSubject.values()); |
| } |
| |
| public Subject getSubject(long userId) { |
| return uniqueIdVsSubject.get(userId); |
| } |
| |
| public boolean removeSubject(long userId) { |
| Subject subject = uniqueIdVsSubject.remove(userId); |
| logger.debug("Subject of {} removed.", userId); |
| if (subject == null) |
| return false; |
| |
| subject.logout(); |
| return true; |
| } |
| |
| public UserAuthAttributes getUserAuthAttributes(String cqName) { |
| // Long uniqueId = cqNameVsUserAuth.get(cqName); |
| // return uniqueIdVsUserAuth.get(uniqueId); |
| return cqNameVsUserAuth.get(cqName); |
| } |
| |
| public void setUserAuthAttributesForCq(String cqName, long uniqueId, boolean isDurable) { |
| UserAuthAttributes uaa = this.uniqueIdVsUserAuth.get(uniqueId); |
| |
| if (uaa != null) { |
| if (!isDurable) |
| this.cqNameVsUserAuth.put(cqName, uaa); |
| else { |
| UserAuthAttributes oldUaa = this.cqNameVsUserAuth.put(cqName, uaa); |
| if (oldUaa != null) { |
| if (oldUaa != uaa)// clean earlier one |
| { |
| this.cleanUserAuth(oldUaa); |
| // add durable(increment) |
| uaa.setDurable(); |
| } else { |
| // if looks extra call from client |
| } |
| } else { |
| uaa.setDurable(); |
| } |
| } |
| } |
| } |
| |
| public void removeUserAuthAttributesForCq(String cqName, boolean isDurable) { |
| UserAuthAttributes uaa = this.cqNameVsUserAuth.remove(cqName); |
| if (uaa != null && isDurable) |
| uaa.unsetDurable(); |
| } |
| |
| public boolean removeUserId(long userId, boolean keepAlive) { |
| UserAuthAttributes uaa = uniqueIdVsUserAuth.get(userId); |
| if (uaa != null && !(uaa.isDurable() && keepAlive)) { |
| uaa = uniqueIdVsUserAuth.remove(userId); |
| logger.debug("UserAuth of {} removed."); |
| if (uaa != null) { |
| cleanUserAuth(uaa); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| |
| public void cleanUserAuth(UserAuthAttributes userAuth) { |
| if (userAuth != null) { |
| AuthorizeRequest authReq = userAuth.getAuthzRequest(); |
| try { |
| if (authReq != null) { |
| authReq.close(); |
| authReq = null; |
| } |
| } catch (Exception ex) { |
| // TODO:hitesh |
| /* |
| * if (securityLogger.warningEnabled()) { securityLogger.warning( LocalizedStrings. |
| * String. |
| * format("%s: An exception was thrown while closing client authorization callback. %s", |
| * new Object[] {"", ex})); } |
| */ |
| } |
| try { |
| AuthorizeRequestPP postAuthzReq = userAuth.getPostAuthzRequest(); |
| if (postAuthzReq != null) { |
| postAuthzReq.close(); |
| postAuthzReq = null; |
| } |
| } catch (Exception ex) { |
| // TODO:hitesh |
| /* |
| * if (securityLogger.warningEnabled()) { securityLogger.warning( LocalizedStrings. |
| * String. |
| * format("%s: An exception was thrown while closing client post-process authorization callback. %s" |
| * , |
| * new Object[] {"", ex})); } |
| */ |
| } |
| } |
| |
| } |
| |
| public void cleanup(boolean fromCacheClientProxy) { |
| for (UserAuthAttributes userAuth : this.uniqueIdVsUserAuth.values()) { |
| // isDurable is checked for multiuser in CQ |
| if (!fromCacheClientProxy && !userAuth.isDurable()) {// from serverConnection class |
| cleanUserAuth(userAuth); |
| } else if (fromCacheClientProxy && userAuth.isDurable()) {// from cacheclientProxy class |
| cleanUserAuth(userAuth); |
| } |
| } |
| |
| // Logout the subjects |
| for (Long subjectId : uniqueIdVsSubject.keySet()) { |
| removeSubject(subjectId); |
| } |
| } |
| |
| public void fillPreviousCQAuth(ClientUserAuths previousClientUserAuths) { |
| for (Iterator<Map.Entry<String, UserAuthAttributes>> iter = |
| previousClientUserAuths.cqNameVsUserAuth.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry<String, UserAuthAttributes> ent = iter.next(); |
| String cqName = ent.getKey(); |
| UserAuthAttributes prevUaa = ent.getValue(); |
| UserAuthAttributes newUaa = this.cqNameVsUserAuth.putIfAbsent(cqName, prevUaa); |
| |
| if (newUaa != null) { |
| previousClientUserAuths.cleanUserAuth(prevUaa); |
| } |
| } |
| } |
| } |