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 019 020 021import java.security.cert.Certificate; 022import java.security.cert.X509Certificate; 023import javax.security.auth.x500.X500Principal; 024 025import org.forgerock.i18n.LocalizableMessage; 026import org.opends.server.admin.std.server.SubjectEqualsDNCertificateMapperCfg; 027import org.opends.server.api.CertificateMapper; 028import org.forgerock.opendj.config.server.ConfigException; 029import org.opends.server.core.DirectoryServer; 030import org.forgerock.i18n.slf4j.LocalizedLogger; 031import org.opends.server.types.*; 032import org.forgerock.opendj.ldap.DN; 033import org.forgerock.opendj.ldap.ResultCode; 034import static org.opends.messages.ExtensionMessages.*; 035import static org.opends.server.util.StaticUtils.*; 036 037/** 038 * This class implements a very simple Directory Server certificate mapper that 039 * will map a certificate to a user only if the subject of the peer certificate 040 * exactly matches the DN of a user in the Directory Server. 041 */ 042public class SubjectEqualsDNCertificateMapper 043 extends CertificateMapper<SubjectEqualsDNCertificateMapperCfg> 044{ 045 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 046 047 /** 048 * Creates a new instance of this certificate mapper. Note that all actual 049 * initialization should be done in the 050 * <CODE>initializeCertificateMapper</CODE> method. 051 */ 052 public SubjectEqualsDNCertificateMapper() 053 { 054 super(); 055 } 056 057 058 059 /** {@inheritDoc} */ 060 @Override 061 public void initializeCertificateMapper(SubjectEqualsDNCertificateMapperCfg 062 configuration) 063 throws ConfigException, InitializationException 064 { 065 // No initialization is required. 066 } 067 068 069 070 /** 071 * Establishes a mapping between the information in the provided certificate 072 * chain to the DN of a single user in the Directory Server. 073 * 074 * @param certificateChain The certificate chain presented by the client 075 * during SSL negotiation. The peer certificate 076 * will be listed first, followed by the ordered 077 * issuer chain as appropriate. 078 * 079 * @return The DN of the one user to whom the mapping was established, or 080 * <CODE>null</CODE> if no mapping was established and no special 081 * message is required to send back to the client. 082 * 083 * @throws DirectoryException If a problem occurred while attempting to 084 * establish the mapping. This may include 085 * internal failures, a mapping which matches 086 * multiple users, or any other case in which an 087 * error message should be returned to the 088 * client. 089 */ 090 @Override 091 public Entry mapCertificateToUser(Certificate[] certificateChain) 092 throws DirectoryException 093 { 094 // Make sure that a peer certificate was provided. 095 if (certificateChain == null || certificateChain.length == 0) 096 { 097 LocalizableMessage message = ERR_SEDCM_NO_PEER_CERTIFICATE.get(); 098 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 099 } 100 101 102 // Get the first certificate in the chain. It must be an X.509 certificate. 103 X509Certificate peerCertificate; 104 try 105 { 106 peerCertificate = (X509Certificate) certificateChain[0]; 107 } 108 catch (Exception e) 109 { 110 logger.traceException(e); 111 112 LocalizableMessage message = ERR_SEDCM_PEER_CERT_NOT_X509.get(certificateChain[0].getType()); 113 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 114 } 115 116 117 // Get the subject from the peer certificate and decode it as a DN. 118 X500Principal peerPrincipal = peerCertificate.getSubjectX500Principal(); 119 DN subjectDN; 120 try 121 { 122 subjectDN = DN.valueOf(peerPrincipal.getName(X500Principal.RFC2253)); 123 } 124 catch (Exception e) 125 { 126 logger.traceException(e); 127 128 LocalizableMessage message = ERR_SEDCM_CANNOT_DECODE_SUBJECT_AS_DN.get(peerPrincipal, getExceptionMessage(e)); 129 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 130 } 131 132 // Retrieve the entry with the specified DN from the directory. 133 Entry userEntry; 134 try 135 { 136 userEntry = DirectoryServer.getEntry(subjectDN); 137 } 138 catch (DirectoryException de) 139 { 140 logger.traceException(de); 141 142 LocalizableMessage message = ERR_SEDCM_CANNOT_GET_ENTRY.get(subjectDN, de.getMessageObject()); 143 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message, de); 144 } 145 catch (Exception e) 146 { 147 logger.traceException(e); 148 149 LocalizableMessage message = ERR_SEDCM_CANNOT_GET_ENTRY.get(subjectDN, getExceptionMessage(e)); 150 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message, e); 151 } 152 153 if (userEntry == null) 154 { 155 LocalizableMessage message = ERR_SEDCM_NO_USER_FOR_DN.get(subjectDN); 156 throw new DirectoryException(ResultCode.INVALID_CREDENTIALS, message); 157 } 158 else 159 { 160 return userEntry; 161 } 162 } 163} 164