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 this.cryptoSessionID = (
062 sessionManager.getCryptoSessionIDPrefix()
063 + '.'
064 + Long.toString(sessionManager.nextCryptoSessionSerial(), 36)
065 + '.'
066 + IdentifierUtil.createRandomID(8)
067 );
068
069 this.userName = userName;
070 // Clone to prevent the password in the session from being nulled, when the outside password is nulled
071 // or the outside password from being corrupted when this session is closed. Marco :-)
072 this.password = password.clone();
073 }
074
075 private String cryptoSessionID;
076 private String userName;
077 private char[] password;
078 private volatile Date lastUse;
079 private volatile Date expiry;
080 private volatile boolean released;
081
082 /**
083 * Get the identifier of this session.
084 * @return the session's unique identifier.
085 */
086 public String getCryptoSessionID() {
087 return cryptoSessionID;
088 }
089
090 public String getUserName() {
091 return userName;
092 }
093 public char[] getPassword() {
094 return password;
095 }
096
097 public Date getLastUse() {
098 return lastUse;
099 }
100
101 protected void updateLastUse(long expiryAgeMSec) {
102 lastUse = new Date();
103 expiry = new Date(lastUse.getTime() + expiryAgeMSec);
104 }
105
106 public Date getExpiry() {
107 return expiry;
108 }
109
110 public void destroy()
111 {
112 SessionManager sm = sessionManager;
113 if (sm == null)
114 return;
115
116 sm.onDestroySession(this);
117
118 sessionManager = null;
119
120 logger.debug("destroy: Destroying session for userName='{}' cryptoSessionID='{}'.", userName, cryptoSessionID);
121
122 char[] pw = password;
123 if (pw != null) {
124 Arrays.fill(pw, (char)0);
125 password = null;
126 }
127
128 cryptoSessionID = null;
129 userName = null;
130 }
131
132 /**
133 * <p>
134 * Set the 'released' status.
135 * </p>
136 * <p>
137 * The application server can only request keys from a session that is currently acquired. That means, a session
138 * should first be acquired, then the app-server should be made to work (on behalf of the client) and finally,
139 * it should be released again.
140 * </p>
141 *
142 * @param released the new 'released' status.
143 */
144 protected void setReleased(boolean released) {
145 this.released = released;
146 }
147
148 public void release() {
149 SessionManager sm = sessionManager;
150 if (sm == null)
151 return;
152
153 sm.onReleaseSession(this);
154 }
155
156 public boolean isReleased() {
157 return released;
158 }
159
160 public void reacquire() {
161 SessionManager sm = sessionManager;
162 if (sm == null)
163 return;
164
165 sm.onReacquireSession(this);
166 }
167 }