blob: cedebe071672c3886ea675b1a6d0777b82dab817 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.security.auth.x500;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.Principal;
import java.util.Map;
import org.apache.harmony.security.x501.Name;
/**
* Represents an X.500 principal, which holds the distinguished name of some
* network entity. An example of a distinguished name is {@code "O=SomeOrg,
* OU=SomeOrgUnit, C=US"}. The class can be instantiated from a byte representation
* of an object identifier (OID), an ASN.1 DER-encoded version, or a simple
* string holding the distinguished name. The representations must follow either
* RFC 2253, RFC 1779, or RFC2459.
*/
public final class X500Principal implements Serializable, Principal {
private static final long serialVersionUID = -500463348111345721L;
/**
* Defines a constant for the canonical string format of distinguished
* names.
*/
public static final String CANONICAL = "CANONICAL";
/**
* Defines a constant for the RFC 1779 string format of distinguished
* names.
*/
public static final String RFC1779 = "RFC1779";
/**
* Defines a constant for the RFC 2253 string format of distinguished
* names.
*/
public static final String RFC2253 = "RFC2253";
//Distinguished Name
private transient Name dn;
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
*
* @param name
* the ASN.1 DER-encoded distinguished name
*
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
public X500Principal(byte[] name) {
if (name == null) {
throw new IllegalArgumentException("Name cannot be null");
}
try {
// FIXME dn = new Name(name);
dn = (Name) Name.ASN1.decode(name);
} catch (IOException e) {
throw incorrectInputEncoding(e);
}
}
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
*
* @param in
* an {@code InputStream} holding the ASN.1 DER-encoded
* distinguished name
*
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
public X500Principal(InputStream in) {
if (in == null) {
throw new NullPointerException("in == null");
}
try {
// FIXME dn = new Name(is);
dn = (Name) Name.ASN1.decode(in);
} catch (IOException e) {
throw incorrectInputEncoding(e);
}
}
private IllegalArgumentException incorrectInputEncoding(IOException e) {
IllegalArgumentException iae = new IllegalArgumentException("Incorrect input encoding");
iae.initCause(e);
throw iae;
}
/**
* Creates a new X500Principal from a string representation of a
* distinguished name.
*
* @param name
* the string representation of the distinguished name
*
* @throws IllegalArgumentException
* if the string representation of the distinguished name is
* incorrect
*/
public X500Principal(String name) {
if (name == null) {
throw new NullPointerException("name == null");
}
try {
dn = new Name(name);
} catch (IOException e) {
throw incorrectInputName(e, name);
}
}
public X500Principal(String name, Map<String,String> keywordMap){
if (name == null) {
throw new NullPointerException("name == null");
}
try {
dn = new Name(substituteNameFromMap(name, keywordMap));
} catch (IOException e) {
throw incorrectInputName(e, name);
}
}
private IllegalArgumentException incorrectInputName(IOException e, String name) {
IllegalArgumentException iae = new IllegalArgumentException("Incorrect input name:" + name);
iae.initCause(e);
throw iae;
}
private transient String canonicalName;
private synchronized String getCanonicalName() {
if (canonicalName == null) {
canonicalName = dn.getName(CANONICAL);
}
return canonicalName;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
X500Principal principal = (X500Principal) o;
return getCanonicalName().equals(principal.getCanonicalName());
}
/**
* Returns an ASN.1 DER-encoded representation of the distinguished name
* contained in this X.500 principal.
*
* @return the ASN.1 DER-encoded representation
*/
public byte[] getEncoded() {
byte[] src = dn.getEncoded();
byte[] dst = new byte[src.length];
System.arraycopy(src, 0, dst, 0, dst.length);
return dst;
}
/**
* Returns a human-readable string representation of the distinguished name
* contained in this X.500 principal.
*
* @return the string representation
*/
public String getName() {
return dn.getName(RFC2253);
}
/**
* Returns a string representation of the distinguished name contained in
* this X.500 principal. The format of the representation can be chosen.
* Valid arguments are {@link #RFC1779}, {@link #RFC2253}, and
* {@link #CANONICAL}. The representations are specified in RFC 1779 and RFC
* 2253, respectively. The canonical form is based on RFC 2253, but adds
* some canonicalizing operations like removing leading and trailing
* whitespace, lower-casing the whole name, and bringing it into a
* normalized Unicode representation.
*
* @param format
* the name of the format to use for the representation
*
* @return the string representation
*
* @throws IllegalArgumentException
* if the {@code format} argument is not one of the three
* mentioned above
*/
public String getName(String format) {
if (CANONICAL.equals(format)) {
return getCanonicalName();
}
return dn.getName(format);
}
public String getName(String format, Map<String, String> oidMap) {
String rfc1779Name = dn.getName(RFC1779);
String rfc2253Name = dn.getName(RFC2253);
if (format.equalsIgnoreCase("RFC1779")) {
StringBuilder resultName = new StringBuilder(rfc1779Name);
int fromIndex = resultName.length();
int equalIndex = -1;
while (-1 != (equalIndex = resultName.lastIndexOf("=", fromIndex))) {
int commaIndex = resultName.lastIndexOf(",", equalIndex);
String subName = resultName.substring(commaIndex + 1,
equalIndex).trim();
if (subName.length() > 4
&& subName.substring(0, 4).equals("OID.")) {
String subSubName = subName.substring(4);
if (oidMap.containsKey(subSubName)) {
String replaceName = oidMap.get(subSubName);
if(commaIndex > 0) replaceName = " " + replaceName;
resultName.replace(commaIndex + 1, equalIndex, replaceName);
}
}
fromIndex = commaIndex;
}
return resultName.toString();
} else if (format.equalsIgnoreCase("RFC2253")) {
StringBuilder resultName = new StringBuilder(rfc2253Name);
StringBuilder subsidyName = new StringBuilder(rfc1779Name);
int fromIndex = resultName.length();
int subsidyFromIndex = subsidyName.length();
int equalIndex = -1;
int subsidyEqualIndex = -1;
while (-1 != (equalIndex = resultName.lastIndexOf("=", fromIndex))) {
subsidyEqualIndex = subsidyName.lastIndexOf("=",
subsidyFromIndex);
int commaIndex = resultName.lastIndexOf(",", equalIndex);
String subName = resultName.substring(commaIndex + 1,
equalIndex).trim();
if (oidMap.containsKey(subName)) {
int subOrignalEndIndex = resultName
.indexOf(",", equalIndex);
if (subOrignalEndIndex == -1)
subOrignalEndIndex = resultName.length();
int subGoalEndIndex = subsidyName.indexOf(",",
subsidyEqualIndex);
if (subGoalEndIndex == -1)
subGoalEndIndex = subsidyName.length();
resultName.replace(equalIndex + 1, subOrignalEndIndex,
subsidyName.substring(subsidyEqualIndex + 1,
subGoalEndIndex));
resultName.replace(commaIndex + 1, equalIndex, oidMap
.get(subName));
}
fromIndex = commaIndex;
subsidyFromIndex = subsidyEqualIndex - 1;
}
return resultName.toString();
} else {
throw new IllegalArgumentException("invalid format specified: " + format);
}
}
@Override
public int hashCode() {
return getCanonicalName().hashCode();
}
@Override
public String toString() {
return dn.getName(RFC1779);
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(dn.getEncoded());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
dn = (Name) Name.ASN1.decode((byte[]) in.readObject());
}
private String substituteNameFromMap(String name, Map<String, String> keywordMap) {
StringBuilder sbName = new StringBuilder(name);
int fromIndex = sbName.length();
int equalIndex;
while (-1 != (equalIndex = sbName.lastIndexOf("=", fromIndex))) {
int commaIndex = sbName.lastIndexOf(",", equalIndex);
String subName = sbName.substring(commaIndex + 1, equalIndex).trim();
if (keywordMap.containsKey(subName)) {
sbName.replace(commaIndex + 1, equalIndex, keywordMap.get(subName));
}
fromIndex = commaIndex;
}
return sbName.toString();
}
}