001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import java.security.cert.Certificate; 020import java.security.cert.X509Certificate; 021import javax.security.auth.x500.X500Principal; 022 023import org.forgerock.i18n.LocalizableMessage; 024import org.forgerock.opendj.server.config.server.SubjectEqualsDNCertificateMapperCfg; 025import org.opends.server.api.CertificateMapper; 026import org.forgerock.opendj.config.server.ConfigException; 027import org.opends.server.core.DirectoryServer; 028import org.forgerock.i18n.slf4j.LocalizedLogger; 029import org.opends.server.types.*; 030import org.forgerock.opendj.ldap.DN; 031import org.forgerock.opendj.ldap.ResultCode; 032import static org.opends.messages.ExtensionMessages.*; 033import static org.opends.server.util.StaticUtils.*; 034 035/** 036 * This class implements a very simple Directory Server certificate mapper that 037 * will map a certificate to a user only if the subject of the peer certificate 038 * exactly matches the DN of a user in the Directory Server. 039 */ 040public class SubjectEqualsDNCertificateMapper 041 extends CertificateMapper<SubjectEqualsDNCertificateMapperCfg> 042{ 043 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 044 045 /** 046 * Creates a new instance of this certificate mapper. Note that all actual 047 * initialization should be done in the 048 * <CODE>initializeCertificateMapper</CODE> method. 049 */ 050 public SubjectEqualsDNCertificateMapper() 051 { 052 super(); 053 } 054 055 @Override 056 public void initializeCertificateMapper(SubjectEqualsDNCertificateMapperCfg 057 configuration) 058 throws ConfigException, InitializationException 059 { 060 // No initialization is required. 061 } 062 063 /** 064 * Establishes a mapping between the information in the provided certificate 065 * chain to the DN of a single user in the Directory Server. 066 * 067 * @param certificateChain The certificate chain presented by the client 068 * during SSL negotiation. The peer certificate 069 * will be listed first, followed by the ordered 070 * issuer chain as appropriate. 071 * 072 * @return The DN of the one user to whom the mapping was established, or 073 * <CODE>null</CODE> if no mapping was established and no special 074 * message is required to send back to the client. 075 * 076 * @throws DirectoryException If a problem occurred while attempting to 077 * establish the mapping. This may include 078 * internal failures, a mapping which matches 079 * multiple users, or any other case in which an 080 * error message should be returned to the 081 * client. 082 */ 083 @Override 084 public Entry mapCertificateToUser(Certificate[] certificateChain) 085 throws DirectoryException 086 { 087 // Make sure that a peer certificate was provided. 088 if (certificateChain == null || certificateChain.length == 0) 089 { 090 LocalizableMessage message = ERR_SEDCM_NO_PEER_CERTIFICATE.get(); 091 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 092 } 093 094 // Get the first certificate in the chain. It must be an X.509 certificate. 095 X509Certificate peerCertificate; 096 try 097 { 098 peerCertificate = (X509Certificate) certificateChain[0]; 099 } 100 catch (Exception e) 101 { 102 logger.traceException(e); 103 104 LocalizableMessage message = ERR_SEDCM_PEER_CERT_NOT_X509.get(certificateChain[0].getType()); 105 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 106 } 107 108 // Get the subject from the peer certificate and decode it as a DN. 109 X500Principal peerPrincipal = peerCertificate.getSubjectX500Principal(); 110 DN subjectDN; 111 try 112 { 113 subjectDN = DN.valueOf(peerPrincipal.getName(X500Principal.RFC2253)); 114 } 115 catch (Exception e) 116 { 117 logger.traceException(e); 118 119 LocalizableMessage message = ERR_SEDCM_CANNOT_DECODE_SUBJECT_AS_DN.get(peerPrincipal, getExceptionMessage(e)); 120 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 121 } 122 123 // Retrieve the entry with the specified DN from the directory. 124 Entry userEntry; 125 try 126 { 127 userEntry = DirectoryServer.getEntry(subjectDN); 128 } 129 catch (DirectoryException de) 130 { 131 logger.traceException(de); 132 133 LocalizableMessage message = ERR_SEDCM_CANNOT_GET_ENTRY.get(subjectDN, de.getMessageObject()); 134 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message, de); 135 } 136 catch (Exception e) 137 { 138 logger.traceException(e); 139 140 LocalizableMessage message = ERR_SEDCM_CANNOT_GET_ENTRY.get(subjectDN, getExceptionMessage(e)); 141 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message, e); 142 } 143 144 if (userEntry == null) 145 { 146 LocalizableMessage message = ERR_SEDCM_NO_USER_FOR_DN.get(subjectDN); 147 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 148 } 149 else 150 { 151 return userEntry; 152 } 153 } 154}