History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/ssl/SSLSessionImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/ssl/SSLSessionImpl.java+832−0
@@ -0,0 +1,832 @@
1/*
2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package sun.security.ssl;
28
29import java.io.*;
30import java.net.*;
31import java.util.Enumeration;
32import java.util.Hashtable;
33import java.util.Vector;
34import java.util.Arrays;
35import java.util.Collection;
36
37import java.security.Principal;
38import java.security.PrivateKey;
39import java.security.SecureRandom;
40import java.security.cert.X509Certificate;
41import java.security.cert.CertificateEncodingException;
42
43import javax.crypto.SecretKey;
44
45import javax.net.ssl.SSLSession;
46import javax.net.ssl.SSLSessionContext;
47import javax.net.ssl.SSLSessionBindingListener;
48import javax.net.ssl.SSLSessionBindingEvent;
49import javax.net.ssl.SSLPeerUnverifiedException;
50import javax.net.ssl.SSLSession;
51import javax.net.ssl.SSLPermission;
52import javax.net.ssl.SSLException;
53import javax.net.ssl.ExtendedSSLSession;
54
55import javax.security.auth.x500.X500Principal;
56
57import static sun.security.ssl.CipherSuite.*;
58import static sun.security.ssl.CipherSuite.KeyExchange.*;
59
60/**
61 * Implements the SSL session interface, and exposes the session context
62 * which is maintained by SSL servers.
63 *
64 * <P> Servers have the ability to manage the sessions associated with
65 * their authentication context(s). They can do this by enumerating the
66 * IDs of the sessions which are cached, examining those sessions, and then
67 * perhaps invalidating a given session so that it can't be used again.
68 * If servers do not explicitly manage the cache, sessions will linger
69 * until memory is low enough that the runtime environment purges cache
70 * entries automatically to reclaim space.
71 *
72 * <P><em> The only reason this class is not package-private is that
73 * there's no other public way to get at the server session context which
74 * is associated with any given authentication context. </em>
75 *
76 * @author David Brownell
77 */
78final class SSLSessionImpl extends ExtendedSSLSession {
79
80 /*
81 * we only really need a single null session
82 */
83 static final SSLSessionImpl nullSession = new SSLSessionImpl();
84
85 // compression methods
86 private static final byte compression_null = 0;
87
88 /*
89 * The state of a single session, as described in section 7.1
90 * of the SSLv3 spec.
91 */
92 private final ProtocolVersion protocolVersion;
93 private final SessionId sessionId;
94 private X509Certificate[] peerCerts;
95 private byte compressionMethod;
96 private CipherSuite cipherSuite;
97 private SecretKey masterSecret;
98
99 /*
100 * Information not part of the SSLv3 protocol spec, but used
101 * to support session management policies.
102 */
103 private final long creationTime = System.currentTimeMillis();
104 private long lastUsedTime = 0;
105 private final String host;
106 private final int port;
107 private SSLSessionContextImpl context;
108 private int sessionCount;
109 private boolean invalidated;
110 private X509Certificate[] localCerts;
111 private PrivateKey localPrivateKey;
112 private String[] localSupportedSignAlgs;
113 private String[] peerSupportedSignAlgs;
114
115 // Principals for non-certificate based cipher suites
116 private Principal peerPrincipal;
117 private Principal localPrincipal;
118
119 /*
120 * We count session creations, eventually for statistical data but
121 * also since counters make shorter debugging IDs than the big ones
122 * we use in the protocol for uniqueness-over-time.
123 */
124 private static volatile int counter = 0;
125
126 /*
127 * Use of session caches is globally enabled/disabled.
128 */
129 private static boolean defaultRejoinable = true;
130
131 /* Class and subclass dynamic debugging support */
132 private static final Debug debug = Debug.getInstance("ssl");
133
134 /*
135 * Create a new non-rejoinable session, using the default (null)
136 * cipher spec. This constructor returns a session which could
137 * be used either by a client or by a server, as a connection is
138 * first opened and before handshaking begins.
139 */
140 private SSLSessionImpl() {
141 this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
142 new SessionId(false, null), null, -1);
143 }
144
145 /*
146 * Create a new session, using a given cipher spec. This will
147 * be rejoinable if session caching is enabled; the constructor
148 * is intended mostly for use by serves.
149 */
150 SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
151 Collection<SignatureAndHashAlgorithm> algorithms,
152 SecureRandom generator, String host, int port) {
153 this(protocolVersion, cipherSuite, algorithms,
154 new SessionId(defaultRejoinable, generator), host, port);
155 }
156
157 /*
158 * Record a new session, using a given cipher spec and session ID.
159 */
160 SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
161 Collection<SignatureAndHashAlgorithm> algorithms,
162 SessionId id, String host, int port) {
163 this.protocolVersion = protocolVersion;
164 sessionId = id;
165 peerCerts = null;
166 compressionMethod = compression_null;
167 this.cipherSuite = cipherSuite;
168 masterSecret = null;
169 this.host = host;
170 this.port = port;
171 sessionCount = ++counter;
172 localSupportedSignAlgs =
173 SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
174
175 if (debug != null && Debug.isOn("session")) {
176 System.out.println("%% Initialized: " + this);
177 }
178 }
179
180 void setMasterSecret(SecretKey secret) {
181 if (masterSecret == null) {
182 masterSecret = secret;
183 } else {
184 throw new RuntimeException("setMasterSecret() error");
185 }
186 }
187
188 /**
189 * Returns the master secret ... treat with extreme caution!
190 */
191 SecretKey getMasterSecret() {
192 return masterSecret;
193 }
194
195 void setPeerCertificates(X509Certificate[] peer) {
196 if (peerCerts == null) {
197 peerCerts = peer;
198 }
199 }
200
201 void setLocalCertificates(X509Certificate[] local) {
202 localCerts = local;
203 }
204
205 void setLocalPrivateKey(PrivateKey privateKey) {
206 localPrivateKey = privateKey;
207 }
208
209 void setPeerSupportedSignatureAlgorithms(
210 Collection<SignatureAndHashAlgorithm> algorithms) {
211 peerSupportedSignAlgs =
212 SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
213 }
214
215 /**
216 * Set the peer principal.
217 */
218 void setPeerPrincipal(Principal principal) {
219 if (peerPrincipal == null) {
220 peerPrincipal = principal;
221 }
222 }
223
224 /**
225 * Set the local principal.
226 */
227 void setLocalPrincipal(Principal principal) {
228 localPrincipal = principal;
229 }
230
231 /**
232 * Returns true iff this session may be resumed ... sessions are
233 * usually resumable. Security policies may suggest otherwise,
234 * for example sessions that haven't been used for a while (say,
235 * a working day) won't be resumable, and sessions might have a
236 * maximum lifetime in any case.
237 */
238 boolean isRejoinable() {
239 return sessionId != null && sessionId.length() != 0 &&
240 !invalidated && isLocalAuthenticationValid();
241 }
242
243 public synchronized boolean isValid() {
244 return isRejoinable();
245 }
246
247 /**
248 * Check if the authentication used when establishing this session
249 * is still valid. Returns true if no authentication was used
250 */
251 boolean isLocalAuthenticationValid() {
252 if (localPrivateKey != null) {
253 try {
254 // if the private key is no longer valid, getAlgorithm()
255 // should throw an exception
256 // (e.g. Smartcard has been removed from the reader)
257 localPrivateKey.getAlgorithm();
258 } catch (Exception e) {
259 invalidate();
260 return false;
261 }
262 }
263 return true;
264 }
265
266 /**
267 * Returns the ID for this session. The ID is fixed for the
268 * duration of the session; neither it, nor its value, changes.
269 */
270 public byte[] getId() {
271 return sessionId.getId();
272 }
273
274 /**
275 * For server sessions, this returns the set of sessions which
276 * are currently valid in this process. For client sessions,
277 * this returns null.
278 */
279 public SSLSessionContext getSessionContext() {
280 /*
281 * An interim security policy until we can do something
282 * more specific in 1.2. Only allow trusted code (code which
283 * can set system properties) to get an
284 * SSLSessionContext. This is to limit the ability of code to
285 * look up specific sessions or enumerate over them. Otherwise,
286 * code can only get session objects from successful SSL
287 * connections which implies that they must have had permission
288 * to make the network connection in the first place.
289 */
290 SecurityManager sm;
291 if ((sm = System.getSecurityManager()) != null) {
292 sm.checkPermission(new SSLPermission("getSSLSessionContext"));
293 }
294
295 return context;
296 }
297
298
299 SessionId getSessionId() {
300 return sessionId;
301 }
302
303
304 /**
305 * Returns the cipher spec in use on this session
306 */
307 CipherSuite getSuite() {
308 return cipherSuite;
309 }
310
311 /**
312 * Resets the cipher spec in use on this session
313 */
314 void setSuite(CipherSuite suite) {
315 cipherSuite = suite;
316
317 if (debug != null && Debug.isOn("session")) {
318 System.out.println("%% Negotiating: " + this);
319 }
320 }
321
322 /**
323 * Returns the name of the cipher suite in use on this session
324 */
325 public String getCipherSuite() {
326 return getSuite().name;
327 }
328
329 ProtocolVersion getProtocolVersion() {
330 return protocolVersion;
331 }
332
333 /**
334 * Returns the standard name of the protocol in use on this session
335 */
336 public String getProtocol() {
337 return getProtocolVersion().name;
338 }
339
340 /**
341 * Returns the compression technique used in this session
342 */
343 byte getCompression() {
344 return compressionMethod;
345 }
346
347 /**
348 * Returns the hashcode for this session
349 */
350 public int hashCode() {
351 return sessionId.hashCode();
352 }
353
354
355 /**
356 * Returns true if sessions have same ids, false otherwise.
357 */
358 public boolean equals(Object obj) {
359
360 if (obj == this) {
361 return true;
362 }
363
364 if (obj instanceof SSLSessionImpl) {
365 SSLSessionImpl sess = (SSLSessionImpl) obj;
366 return (sessionId != null) && (sessionId.equals(
367 sess.getSessionId()));
368 }
369
370 return false;
371 }
372
373
374 /**
375 * Return the cert chain presented by the peer in the
376 * java.security.cert format.
377 * Note: This method can be used only when using certificate-based
378 * cipher suites; using it with non-certificate-based cipher suites,
379 * such as Kerberos, will throw an SSLPeerUnverifiedException.
380 *
381 * @return array of peer X.509 certs, with the peer's own cert
382 * first in the chain, and with the "root" CA last.
383 */
384 public java.security.cert.Certificate[] getPeerCertificates()
385 throws SSLPeerUnverifiedException {
386 //
387 // clone to preserve integrity of session ... caller can't
388 // change record of peer identity even by accident, much
389 // less do it intentionally.
390 //
391 if ((cipherSuite.keyExchange == K_KRB5) ||
392 (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
393 throw new SSLPeerUnverifiedException("no certificates expected"
394 + " for Kerberos cipher suites");
395 }
396 if (peerCerts == null) {
397 throw new SSLPeerUnverifiedException("peer not authenticated");
398 }
399 // Certs are immutable objects, therefore we don't clone them.
400 // But do need to clone the array, so that nothing is inserted
401 // into peerCerts.
402 return (java.security.cert.Certificate[])peerCerts.clone();
403 }
404
405 /**
406 * Return the cert chain presented to the peer in the
407 * java.security.cert format.
408 * Note: This method is useful only when using certificate-based
409 * cipher suites.
410 *
411 * @return array of peer X.509 certs, with the peer's own cert
412 * first in the chain, and with the "root" CA last.
413 */
414 public java.security.cert.Certificate[] getLocalCertificates() {
415 //
416 // clone to preserve integrity of session ... caller can't
417 // change record of peer identity even by accident, much
418 // less do it intentionally.
419 return (localCerts == null ? null :
420 (java.security.cert.Certificate[])localCerts.clone());
421 }
422
423 /**
424 * Return the cert chain presented by the peer in the
425 * javax.security.cert format.
426 * Note: This method can be used only when using certificate-based
427 * cipher suites; using it with non-certificate-based cipher suites,
428 * such as Kerberos, will throw an SSLPeerUnverifiedException.
429 *
430 * @return array of peer X.509 certs, with the peer's own cert
431 * first in the chain, and with the "root" CA last.
432 */
433 public javax.security.cert.X509Certificate[] getPeerCertificateChain()
434 throws SSLPeerUnverifiedException {
435 //
436 // clone to preserve integrity of session ... caller can't
437 // change record of peer identity even by accident, much
438 // less do it intentionally.
439 //
440 if ((cipherSuite.keyExchange == K_KRB5) ||
441 (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
442 throw new SSLPeerUnverifiedException("no certificates expected"
443 + " for Kerberos cipher suites");
444 }
445 if (peerCerts == null) {
446 throw new SSLPeerUnverifiedException("peer not authenticated");
447 }
448 javax.security.cert.X509Certificate[] certs;
449 certs = new javax.security.cert.X509Certificate[peerCerts.length];
450 for (int i = 0; i < peerCerts.length; i++) {
451 byte[] der = null;
452 try {
453 der = peerCerts[i].getEncoded();
454 certs[i] = javax.security.cert.X509Certificate.getInstance(der);
455 } catch (CertificateEncodingException e) {
456 throw new SSLPeerUnverifiedException(e.getMessage());
457 } catch (javax.security.cert.CertificateException e) {
458 throw new SSLPeerUnverifiedException(e.getMessage());
459 }
460 }
461
462 return certs;
463 }
464
465 /**
466 * Return the cert chain presented by the peer.
467 * Note: This method can be used only when using certificate-based
468 * cipher suites; using it with non-certificate-based cipher suites,
469 * such as Kerberos, will throw an SSLPeerUnverifiedException.
470 *
471 * @return array of peer X.509 certs, with the peer's own cert
472 * first in the chain, and with the "root" CA last.
473 */
474 public X509Certificate[] getCertificateChain()
475 throws SSLPeerUnverifiedException {
476 /*
477 * clone to preserve integrity of session ... caller can't
478 * change record of peer identity even by accident, much
479 * less do it intentionally.
480 */
481 if ((cipherSuite.keyExchange == K_KRB5) ||
482 (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
483 throw new SSLPeerUnverifiedException("no certificates expected"
484 + " for Kerberos cipher suites");
485 }
486 if (peerCerts != null) {
487 return peerCerts.clone();
488 } else {
489 throw new SSLPeerUnverifiedException("peer not authenticated");
490 }
491 }
492
493 /**
494 * Returns the identity of the peer which was established as part of
495 * defining the session.
496 *
497 * @return the peer's principal. Returns an X500Principal of the
498 * end-entity certificate for X509-based cipher suites, and
499 * Principal for Kerberos cipher suites.
500 *
501 * @throws SSLPeerUnverifiedException if the peer's identity has not
502 * been verified
503 */
504 public Principal getPeerPrincipal()
505 throws SSLPeerUnverifiedException
506 {
507 if ((cipherSuite.keyExchange == K_KRB5) ||
508 (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
509 if (peerPrincipal == null) {
510 throw new SSLPeerUnverifiedException("peer not authenticated");
511 } else {
512 // Eliminate dependency on KerberosPrincipal
513 return peerPrincipal;
514 }
515 }
516 if (peerCerts == null) {
517 throw new SSLPeerUnverifiedException("peer not authenticated");
518 }
519 return peerCerts[0].getSubjectX500Principal();
520 }
521
522 /**
523 * Returns the principal that was sent to the peer during handshaking.
524 *
525 * @return the principal sent to the peer. Returns an X500Principal
526 * of the end-entity certificate for X509-based cipher suites, and
527 * Principal for Kerberos cipher suites. If no principal was
528 * sent, then null is returned.
529 */
530 public Principal getLocalPrincipal() {
531
532 if ((cipherSuite.keyExchange == K_KRB5) ||
533 (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
534 // Eliminate dependency on KerberosPrincipal
535 return (localPrincipal == null ? null : localPrincipal);
536 }
537 return (localCerts == null ? null :
538 localCerts[0].getSubjectX500Principal());
539 }
540
541 /**
542 * Returns the time this session was created.
543 */
544 public long getCreationTime() {
545 return creationTime;
546 }
547
548 /**
549 * Returns the last time this session was used to initialize
550 * a connection.
551 */
552 public long getLastAccessedTime() {
553 return (lastUsedTime != 0) ? lastUsedTime : creationTime;
554 }
555
556 void setLastAccessedTime(long time) {
557 lastUsedTime = time;
558 }
559
560
561 /**
562 * Returns the network address of the session's peer. This
563 * implementation does not insist that connections between
564 * different ports on the same host must necessarily belong
565 * to different sessions, though that is of course allowed.
566 */
567 public InetAddress getPeerAddress() {
568 try {
569 return InetAddress.getByName(host);
570 } catch (java.net.UnknownHostException e) {
571 return null;
572 }
573 }
574
575 public String getPeerHost() {
576 return host;
577 }
578
579 /**
580 * Need to provide the port info for caching sessions based on
581 * host and port. Accessed by SSLSessionContextImpl
582 */
583 public int getPeerPort() {
584 return port;
585 }
586
587 void setContext(SSLSessionContextImpl ctx) {
588 if (context == null) {
589 context = ctx;
590 }
591 }
592
593 /**
594 * Invalidate a session. Active connections may still exist, but
595 * no connections will be able to rejoin this session.
596 */
597 synchronized public void invalidate() {
598 //
599 // Can't invalidate the NULL session -- this would be
600 // attempted when we get a handshaking error on a brand
601 // new connection, with no "real" session yet.
602 //
603 if (this == nullSession) {
604 return;
605 }
606 invalidated = true;
607 if (debug != null && Debug.isOn("session")) {
608 System.out.println("%% Invalidated: " + this);
609 }
610 if (context != null) {
611 context.remove(sessionId);
612 context = null;
613 }
614 }
615
616 /*
617 * Table of application-specific session data indexed by an application
618 * key and the calling security context. This is important since
619 * sessions can be shared across different protection domains.
620 */
621 private Hashtable<SecureKey, Object> table = new Hashtable<>();
622
623 /**
624 * Assigns a session value. Session change events are given if
625 * appropriate, to any original value as well as the new value.
626 */
627 public void putValue(String key, Object value) {
628 if ((key == null) || (value == null)) {
629 throw new IllegalArgumentException("arguments can not be null");
630 }
631
632 SecureKey secureKey = new SecureKey(key);
633 Object oldValue = table.put(secureKey, value);
634
635 if (oldValue instanceof SSLSessionBindingListener) {
636 SSLSessionBindingEvent e;
637
638 e = new SSLSessionBindingEvent(this, key);
639 ((SSLSessionBindingListener)oldValue).valueUnbound(e);
640 }
641 if (value instanceof SSLSessionBindingListener) {
642 SSLSessionBindingEvent e;
643
644 e = new SSLSessionBindingEvent(this, key);
645 ((SSLSessionBindingListener)value).valueBound(e);
646 }
647 }
648
649
650 /**
651 * Returns the specified session value.
652 */
653 public Object getValue(String key) {
654 if (key == null) {
655 throw new IllegalArgumentException("argument can not be null");
656 }
657
658 SecureKey secureKey = new SecureKey(key);
659 return table.get(secureKey);
660 }
661
662
663 /**
664 * Removes the specified session value, delivering a session changed
665 * event as appropriate.
666 */
667 public void removeValue(String key) {
668 if (key == null) {
669 throw new IllegalArgumentException("argument can not be null");
670 }
671
672 SecureKey secureKey = new SecureKey(key);
673 Object value = table.remove(secureKey);
674
675 if (value instanceof SSLSessionBindingListener) {
676 SSLSessionBindingEvent e;
677
678 e = new SSLSessionBindingEvent(this, key);
679 ((SSLSessionBindingListener)value).valueUnbound(e);
680 }
681 }
682
683
684 /**
685 * Lists the names of the session values.
686 */
687 public String[] getValueNames() {
688 Enumeration<SecureKey> e;
689 Vector<Object> v = new Vector<>();
690 SecureKey key;
691 Object securityCtx = SecureKey.getCurrentSecurityContext();
692
693 for (e = table.keys(); e.hasMoreElements(); ) {
694 key = e.nextElement();
695
696 if (securityCtx.equals(key.getSecurityContext())) {
697 v.addElement(key.getAppKey());
698 }
699 }
700 String[] names = new String[v.size()];
701 v.copyInto(names);
702
703 return names;
704 }
705
706 /**
707 * Use large packet sizes now or follow RFC 2246 packet sizes (2^14)
708 * until changed.
709 *
710 * In the TLS specification (section 6.2.1, RFC2246), it is not
711 * recommended that the plaintext has more than 2^14 bytes.
712 * However, some TLS implementations violate the specification.
713 * This is a workaround for interoperability with these stacks.
714 *
715 * Application could accept large fragments up to 2^15 bytes by
716 * setting the system property jsse.SSLEngine.acceptLargeFragments
717 * to "true".
718 */
719 private boolean acceptLargeFragments =
720 Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false);
721
722 /**
723 * Expand the buffer size of both SSL/TLS network packet and
724 * application data.
725 */
726 protected synchronized void expandBufferSizes() {
727 acceptLargeFragments = true;
728 }
729
730 /**
731 * Gets the current size of the largest SSL/TLS packet that is expected
732 * when using this session.
733 */
734 public synchronized int getPacketBufferSize() {
735 return acceptLargeFragments ?
736 Record.maxLargeRecordSize : Record.maxRecordSize;
737 }
738
739 /**
740 * Gets the current size of the largest application data that is
741 * expected when using this session.
742 */
743 public synchronized int getApplicationBufferSize() {
744 return getPacketBufferSize() - Record.headerSize;
745 }
746
747 /**
748 * Gets an array of supported signature algorithms that the local side is
749 * willing to verify.
750 */
751 public String[] getLocalSupportedSignatureAlgorithms() {
752 if (localSupportedSignAlgs != null) {
753 return localSupportedSignAlgs.clone();
754 }
755
756 return new String[0];
757 }
758
759 /**
760 * Gets an array of supported signature algorithms that the peer is
761 * able to verify.
762 */
763 public String[] getPeerSupportedSignatureAlgorithms() {
764 if (peerSupportedSignAlgs != null) {
765 return peerSupportedSignAlgs.clone();
766 }
767
768 return new String[0];
769 }
770
771 /** Returns a string representation of this SSL session */
772 public String toString() {
773 return "[Session-" + sessionCount
774 + ", " + getCipherSuite()
775 + "]";
776 }
777
778 /**
779 * When SSL sessions are finalized, all values bound to
780 * them are removed.
781 */
782 public void finalize() {
783 String[] names = getValueNames();
784 for (int i = 0; i < names.length; i++) {
785 removeValue(names[i]);
786 }
787 }
788}
789
790
791/**
792 * This "struct" class serves as a Hash Key that combines an
793 * application-specific key and a security context.
794 */
795class SecureKey {
796 private static Object nullObject = new Object();
797 private Object appKey;
798 private Object securityCtx;
799
800 static Object getCurrentSecurityContext() {
801 SecurityManager sm = System.getSecurityManager();
802 Object context = null;
803
804 if (sm != null)
805 context = sm.getSecurityContext();
806 if (context == null)
807 context = nullObject;
808 return context;
809 }
810
811 SecureKey(Object key) {
812 this.appKey = key;
813 this.securityCtx = getCurrentSecurityContext();
814 }
815
816 Object getAppKey() {
817 return appKey;
818 }
819
820 Object getSecurityContext() {
821 return securityCtx;
822 }
823
824 public int hashCode() {
825 return appKey.hashCode() ^ securityCtx.hashCode();
826 }
827
828 public boolean equals(Object o) {
829 return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey)
830 && ((SecureKey)o).securityCtx.equals(securityCtx);
831 }
832}