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