Coverage Report - org.openpermis.repository.basic.AbstractSubjectRepository
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractSubjectRepository
75%
27/36
75%
9/12
5.25
 
 1  
 /*
 2  
  * Copyright (c) 2009, Swiss Federal Department of Defence Civil Protection and Sport
 3  
  *                     (http://www.vbs.admin.ch)
 4  
  * Copyright (c) 2009, Ergon Informatik AG (http://www.ergon.ch)
 5  
  * All rights reserved.
 6  
  *
 7  
  * Licensed under the Open Permis License which accompanies this distribution,
 8  
  * and is available at http://www.openpermis.org/BSDlicenceKent.txt
 9  
  */
 10  
 package org.openpermis.repository.basic;
 11  
 
 12  
 
 13  
 import static org.openpermis.cert.AttributeCertificateExtractorUtility.toUri;
 14  
 
 15  
 import java.net.URI;
 16  
 import java.security.InvalidKeyException;
 17  
 import java.security.NoSuchAlgorithmException;
 18  
 import java.security.NoSuchProviderException;
 19  
 import java.security.SignatureException;
 20  
 import java.security.cert.Certificate;
 21  
 import java.security.cert.CertificateException;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import org.openpermis.basic.InternalSubject;
 26  
 import org.openpermis.basic.TimePeriod;
 27  
 import org.openpermis.cert.AttributeCertificate;
 28  
 import org.openpermis.cert.AttributeCertificateException;
 29  
 import org.openpermis.cert.AttributeCertificateExtractorUtility;
 30  
 import org.openpermis.cert.CertificateVerifier;
 31  
 import org.openpermis.cert.RoleAttribute.RoleDefinition;
 32  
 import org.openpermis.repository.SubjectRepository;
 33  
 
 34  
 
 35  
 /**
 36  
  * An abstract subject repository with all code used (or usable) by subclasses.
 37  
  * @since 0.1.0
 38  
  */
 39  
 public abstract class AbstractSubjectRepository
 40  
         implements SubjectRepository
 41  
 {
 42  
 
 43  
         //---- State
 44  
         
 45  
         /**
 46  
          * The internally user class to verify certificates. 
 47  
          * @since 0.3.0
 48  
          */
 49  
         private final CertificateVerifier certificateVerifier;
 50  
         
 51  
         //---- Constructors
 52  
         
 53  
         /**
 54  
          * Creates an abstract subject repository and uses the specified certificate verifier
 55  
          * to validate the attribute certificates. 
 56  
          * 
 57  
          * @param certificateVerifier The certificate verifier user to verify the the attribute
 58  
          * certificates. Must not be <code>null</code>.
 59  
          * @since 0.3.0
 60  
          */
 61  6
         protected AbstractSubjectRepository (CertificateVerifier certificateVerifier) {
 62  6
                 if (certificateVerifier == null) {
 63  0
                         throw new IllegalArgumentException("certificate verifier is null");
 64  
                 }
 65  6
                 this.certificateVerifier = certificateVerifier;
 66  6
         }
 67  
         
 68  
         //---- Methods
 69  
         
 70  
         /**
 71  
          * Updates the specified subject-by-identity map by processing the specified attribute 
 72  
          * certificate and assigning roles to all affected subjects. If a subject does not yet exist, it
 73  
          * is created and stored in the map.
 74  
          * 
 75  
          * This method does <em>not</em> synchronize anything. Thus, if a subclass intends to be
 76  
          * thread-safe, it must itself lock the map accordingly.
 77  
          * 
 78  
          * @param subjectsByIdentity A map storing subjects by their identities. Must not be 
 79  
          * <code>null</code>.
 80  
          * @param certificate The attribute certificate to process. May be null.
 81  
          * @since 0.1.0
 82  
          */
 83  
         protected void updateSubjectMap (
 84  
                 Map<URI, InternalSubject> subjectsByIdentity, 
 85  
                 AttributeCertificate certificate
 86  
         ) 
 87  
                 throws NoSuchAlgorithmException, NoSuchProviderException 
 88  
         {
 89  12
                 if (subjectsByIdentity == null) {
 90  0
                         throw new IllegalArgumentException("subject map is null");
 91  
                 }
 92  12
                 if (certificate == null) {
 93  0
                         return;
 94  
                 }
 95  12
                 if (!isCertificateCorrect(certificate)) {
 96  4
                         return;
 97  
                 }        
 98  
                 
 99  
                 try {
 100  8
                         final URI issuer = toUri(AttributeCertificateExtractorUtility.readIssuer(certificate));
 101  8
                         final URI holder = toUri(AttributeCertificateExtractorUtility.readHolder(certificate));
 102  8
                         final InternalSubject holderSubject = getOrCreateSubject(subjectsByIdentity, holder);
 103  8
                         final TimePeriod validity = 
 104  
                                 AttributeCertificateExtractorUtility.readValidityPeriod(certificate);
 105  8
                         final List<RoleDefinition> roles = 
 106  
                                 AttributeCertificateExtractorUtility.readRoleAttribute(certificate);
 107  
                         
 108  
                         // Assign all roles to subject.
 109  8
                         for (RoleDefinition role : roles) {
 110  8
                                 holderSubject.assignRole(
 111  
                                         getOrCreateSubject(subjectsByIdentity, issuer),
 112  
                                         role.getName(), 
 113  
                                         URI.create(role.getHierarchy()), 
 114  
                                         validity
 115  
                                 );
 116  
                         }
 117  
                 
 118  0
                 } catch (AttributeCertificateException e) {
 119  
                         // Ignore this certificate.
 120  0
                         return;
 121  8
                 }
 122  8
         }
 123  
         
 124  
         /**
 125  
          * Checks if the specified certificate is valid. What is done exactly depends
 126  
          * on the certificate verifier this class uses.
 127  
          * 
 128  
          * @return <code>true</code> if (and only if) the certificate could be verified.
 129  
          * @throws NoSuchProviderException Thrown if there is no default crypto provider.
 130  
          * @throws NoSuchAlgorithmException Thrown if a cryptographic algorithm used for signature 
 131  
          * verification cannot be retrieved from the crypto provider(s).
 132  
          * @since 0.1.0
 133  
          * @since 0.3.0 changed to private.
 134  
          */
 135  
         private boolean isCertificateCorrect (Certificate certificate) 
 136  
                 throws NoSuchAlgorithmException, NoSuchProviderException 
 137  
         {
 138  
                 try {
 139  12
                         this.certificateVerifier.verifyCertificate(certificate);
 140  4
                 } catch (InvalidKeyException e) {
 141  4
                         return false;
 142  0
                 } catch (CertificateException e) {
 143  0
                         return false;
 144  0
                 } catch (SignatureException e) {
 145  0
                         return false;
 146  8
                 }
 147  8
                 return true;
 148  
         }
 149  
 
 150  
         /**
 151  
          * Internal method looking up a subject and creating it if it does not exist.
 152  
          */
 153  
         private InternalSubject getOrCreateSubject (
 154  
                 Map<URI, InternalSubject> subjectsByIdentity, 
 155  
                 URI identity
 156  
         ) {
 157  
                 final InternalSubject result;
 158  16
                 if (subjectsByIdentity.containsKey(identity)) {
 159  4
                         result = subjectsByIdentity.get(identity);
 160  
                 } else {
 161  12
                         result = new InternalSubject(identity);
 162  12
                         subjectsByIdentity.put(identity, result);
 163  
                 }
 164  16
                 return result;
 165  
         }
 166  
         
 167  
 }