001 /*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018 package org.cumulus4j.keymanager;
019
020 import java.util.Arrays;
021 import java.util.Date;
022
023 import org.cumulus4j.keymanager.back.shared.IdentifierUtil;
024 import org.slf4j.Logger;
025 import org.slf4j.LoggerFactory;
026
027 /**
028 * <p>
029 * Session to control and restrict the key exchange with the application server.
030 * </p>
031 * <p>
032 * In order to protect the keys as well as possible, keys can only be requested from an application
033 * server within the scope of a so-called crypto-session. The client controls when to open/close a crypto-session
034 * and when to allow keys to be transferred. Key transfer is only possible while a session is {@link #setReleased(boolean) unlocked}.
035 * </p>
036 * <p>
037 * This is not API! Use the classes and interfaces provided by <code>org.cumulus4j.keymanager.api</code> instead.
038 * </p>
039 *
040 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
041 */
042 public class Session
043 {
044 private static final Logger logger = LoggerFactory.getLogger(Session.class);
045
046 private SessionManager sessionManager;
047
048 protected Session(SessionManager sessionManager, String userName, char[] password)
049 {
050 if (sessionManager == null)
051 throw new IllegalArgumentException("sessionManager == null");
052
053 if (userName == null)
054 throw new IllegalArgumentException("userName == null");
055
056 if (password == null)
057 throw new IllegalArgumentException("password == null");
058
059 this.sessionManager = sessionManager;
060
061 // see org.cumulus4j.keymanager.back.shared.Request#getCryptoSessionIDPrefix()
062 // see org.cumulus4j.store.crypto.AbstractCryptoSession#getKeyStoreID()
063 this.cryptoSessionID = (
064 sessionManager.getCryptoSessionIDPrefix()
065 + '*'
066 + Long.toString(sessionManager.nextCryptoSessionSerial(), 36)
067 + '*'
068 + IdentifierUtil.createRandomID(6)
069 );
070
071 this.userName = userName;
072 // Clone to prevent the password in the session from being nulled, when the outside password is nulled
073 // or the outside password from being corrupted when this session is closed. Marco :-)
074 this.password = password.clone();
075 }
076
077 private String cryptoSessionID;
078 private String userName;
079 private char[] password;
080 private volatile Date lastUse;
081 private volatile Date expiry;
082 private volatile boolean released;
083
084 /**
085 * Get the identifier of this session.
086 * @return the session's unique identifier.
087 */
088 public String getCryptoSessionID() {
089 return cryptoSessionID;
090 }
091
092 public String getUserName() {
093 return userName;
094 }
095 public char[] getPassword() {
096 return password;
097 }
098
099 public Date getLastUse() {
100 return lastUse;
101 }
102
103 protected void updateLastUse(long expiryAgeMSec) {
104 lastUse = new Date();
105 expiry = new Date(lastUse.getTime() + expiryAgeMSec);
106 }
107
108 public Date getExpiry() {
109 return expiry;
110 }
111
112 public void destroy()
113 {
114 SessionManager sm = sessionManager;
115 if (sm == null)
116 return;
117
118 sm.onDestroySession(this);
119
120 sessionManager = null;
121
122 logger.debug("destroy: Destroying session for userName='{}' cryptoSessionID='{}'.", userName, cryptoSessionID);
123
124 char[] pw = password;
125 if (pw != null) {
126 Arrays.fill(pw, (char)0);
127 password = null;
128 }
129
130 cryptoSessionID = null;
131 userName = null;
132 }
133
134 /**
135 * <p>
136 * Set the 'released' status.
137 * </p>
138 * <p>
139 * The application server can only request keys from a session that is currently acquired. That means, a session
140 * should first be acquired, then the app-server should be made to work (on behalf of the client) and finally,
141 * it should be released again.
142 * </p>
143 *
144 * @param released the new 'released' status.
145 */
146 protected void setReleased(boolean released) {
147 this.released = released;
148 }
149
150 public void release() {
151 SessionManager sm = sessionManager;
152 if (sm == null)
153 return;
154
155 sm.onReleaseSession(this);
156 }
157
158 public boolean isReleased() {
159 return released;
160 }
161
162 public void reacquire() {
163 SessionManager sm = sessionManager;
164 if (sm == null)
165 return;
166
167 sm.onReacquireSession(this);
168 }
169 }