/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.web.ha.authenticator;
import com.sun.enterprise.container.common.spi.util.JavaEEIOUtils;
import org.apache.catalina.Container;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.SingleSignOn;
import org.apache.catalina.authenticator.SingleSignOnEntry;
import org.glassfish.web.ha.LogFacade;
import org.glassfish.web.ha.session.management.HAStoreBase;
import java.io.*;
import java.security.Principal;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Shing Wai Chan
*/
public class HASingleSignOnEntry extends SingleSignOnEntry {
private static final Logger logger = LogFacade.getLogger();
protected long maxIdleTime;
protected JavaEEIOUtils ioUtils;
protected HASingleSignOnEntryMetadata metadata = null;
// default constructor is required by backing store
public HASingleSignOnEntry() {
this(null, null, null, null, null, 0, 0, 0, null, null);
}
public HASingleSignOnEntry(Container container, HASingleSignOnEntryMetadata m,
JavaEEIOUtils ioUtils) {
this(m.getId(), null, m.getAuthType(),
m.getUserName(), m.getRealmName(),
m.getLastAccessTime(), m.getMaxIdleTime(), m.getVersion(),
ioUtils, m.getPrincipalBytes());
for (HASessionData data: m.getHASessionDataSet()) {
StandardContext context = (StandardContext)container.findChild(data.getContextPath());
Session session = null;
try {
session = context.getManager().findSession(data.getSessionId());
} catch(IOException ex) {
throw new IllegalStateException(ex);
}
if (session != null) {
sessions.add(session);
}
}
}
public HASingleSignOnEntry(String id, Principal principal, String authType,
String username, String realmName,
long lastAccessTime, long maxIdleTime, long version,
JavaEEIOUtils ioUtils) {
this(id, principal, authType, username, realmName, lastAccessTime,
maxIdleTime, version, ioUtils, convertToByteArray(principal, ioUtils));
}
private HASingleSignOnEntry(String id, Principal principal, String authType,
String username, String realmName,
long lastAccessTime, long maxIdleTime, long version,
JavaEEIOUtils ioUtils, byte[] principalBytes) {
super(id, version, principal, authType, username, realmName);
this.lastAccessTime = lastAccessTime;
this.maxIdleTime = maxIdleTime;
this.ioUtils = ioUtils;
if (principal == null && principalBytes != null) {
this.principal = parse(principalBytes);
}
metadata = new HASingleSignOnEntryMetadata(
id, version, principalBytes, authType,
username, realmName,
lastAccessTime, maxIdleTime);
if (logger.isLoggable(Level.FINER)) {
String pName = ((principal != null)? principal.getName() : null);
logger.log(Level.FINER, "Loaded HA SSO entry with principal: " + pName);
}
}
public HASingleSignOnEntryMetadata getMetadata() {
return metadata;
}
public long getMaxIdleTime() {
return maxIdleTime;
}
@Override
public synchronized boolean addSession(SingleSignOn sso, Session session) {
boolean result = super.addSession(sso, session);
if (result) {
metadata.addHASessionData(new HASessionData(session.getId(),
session.getManager().getContainer().getName()));
}
return result;
}
@Override
public synchronized void removeSession(Session session) {
super.removeSession(session);
metadata.removeHASessionData(new HASessionData(session.getId(),
session.getManager().getContainer().getName()));
}
@Override
public void setLastAccessTime(long lastAccessTime) {
super.setLastAccessTime(lastAccessTime);
metadata.setLastAccessTime(lastAccessTime);
}
@Override
public long incrementAndGetVersion() {
long ver = super.incrementAndGetVersion();
metadata.setVersion(ver);
return ver;
}
// convert a Principal object into byte array
private static byte[] convertToByteArray(Principal obj, JavaEEIOUtils ioUtils) {
ByteArrayOutputStream baos = null;
BufferedOutputStream bos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
bos = new BufferedOutputStream(baos);
oos = ioUtils.createObjectOutputStream(bos, true);
oos.writeObject(obj);
oos.flush();
return baos.toByteArray();
} catch(Exception ex) {
throw new IllegalStateException(ex);
} finally {
closeSafely(baos);
closeSafely(bos);
closeSafely(oos);
}
}
private static void closeSafely(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch(IOException ex) {
// ignore
}
}
}
private Principal parse(byte[] pbytes) {
ByteArrayInputStream bais = null;
BufferedInputStream bis = null;
ObjectInputStream ois = null;
try {
bais = new ByteArrayInputStream(pbytes);
bis = new BufferedInputStream(bais);
ois = ioUtils.createObjectInputStream(bis, true, this.getClass().getClassLoader());
return (Principal)ois.readObject();
} catch(Exception ex) {
throw new IllegalStateException(ex);
} finally {
closeSafely(bais);
closeSafely(bis);
closeSafely(ois);
}
}
}