001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.core;
021    
022    
023    import java.io.Externalizable;
024    import java.io.IOException;
025    import java.io.ObjectInput;
026    import java.io.ObjectOutput;
027    import java.security.Principal;
028    
029    import org.apache.directory.server.i18n.I18n;
030    import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
031    import org.apache.directory.shared.ldap.name.DN;
032    import org.apache.directory.shared.ldap.util.StringTools;
033    
034    
035    /**
036     * An alternative X500 user implementation that has access to the distinguished
037     * name of the principal as well as the String representation.
038     *
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev: 918766 $
041     */
042    public final class LdapPrincipal implements Principal, Cloneable, Externalizable
043    {
044        private static final long serialVersionUID = 3906650782395676720L;
045    
046        /** the normalized distinguished name of the principal */
047        private DN name;
048    
049        /** the no name anonymous user whose DN is the empty String */
050        public static final LdapPrincipal ANONYMOUS = new LdapPrincipal();
051    
052        /** the authentication level for this principal */
053        private AuthenticationLevel authenticationLevel;
054        
055        /** The userPassword
056         * @todo security risk remove this immediately
057         * The field is transient to avoid being serialized
058         */
059        transient private byte[] userPassword;
060    
061    
062        /**
063         * Creates a new LDAP/X500 principal without any group associations.  Keep
064         * this package friendly so only code in the package can create a
065         * trusted principal.
066         *
067         * @param name the normalized distinguished name of the principal
068         * @param authenticationLevel the authentication level for this principal
069         */
070        public LdapPrincipal( DN name, AuthenticationLevel authenticationLevel )
071        {
072            this.name = name;
073            
074            if ( ! name.isNormalized() )
075            {
076                throw new IllegalStateException( I18n.err( I18n.ERR_436 ) );
077            }
078            
079            this.authenticationLevel = authenticationLevel;
080            this.userPassword = null;
081        }
082    
083        /**
084         * Creates a new LDAP/X500 principal without any group associations.  Keep
085         * this package friendly so only code in the package can create a
086         * trusted principal.
087         *
088         * @param name the normalized distinguished name of the principal
089         * @param authenticationLevel the authentication level for this principal
090         * @param userPassword The user password
091         */
092        public LdapPrincipal( DN name, AuthenticationLevel authenticationLevel, byte[] userPassword )
093        {
094            this.name = name;
095            this.authenticationLevel = authenticationLevel;
096            this.userPassword = new byte[ userPassword.length ];
097            System.arraycopy( userPassword, 0, this.userPassword, 0, userPassword.length );
098        }
099    
100    
101        /**
102         * Creates a principal for the no name anonymous user whose DN is the empty
103         * String.
104         */
105        public LdapPrincipal()
106        {
107            name = new DN();
108            authenticationLevel = AuthenticationLevel.NONE;
109            userPassword = null;
110        }
111    
112    
113        /**
114         * Gets a cloned copy of the normalized distinguished name of this
115         * principal as a {@link DN}.
116         *
117         * @return the cloned distinguished name of the principal as a {@link DN}
118         */
119        public DN getClonedName()
120        {
121            return ( DN ) name.clone();
122        }
123    
124    
125        /**
126         * Returns the normalized distinguished name of the principal as a String.
127         */
128        public String getName()
129        {
130            return name.getNormName();
131        }
132    
133    
134        /**
135         * Gets the authentication level associated with this LDAP principle.
136         *
137         * @return the authentication level
138         */
139        public AuthenticationLevel getAuthenticationLevel()
140        {
141            return authenticationLevel;
142        }
143    
144    
145        /**
146         * Returns string representation of the normalized distinguished name
147         * of this principal.
148         */
149        public String toString()
150        {
151            return "['" + name.getName() + "', '" + StringTools.utf8ToString( userPassword ) +"']'";
152        }
153    
154    
155        public byte[] getUserPassword()
156        {
157            return userPassword;
158        }
159    
160    
161        public void setUserPassword( byte[] userPassword )
162        {
163            this.userPassword = new byte[ userPassword.length ];
164            System.arraycopy( userPassword, 0, this.userPassword, 0, userPassword.length );
165        }
166        
167        
168        /**
169         * Clone the object. This is done so that we don't store the 
170         * password in a LdapPrincipal more than necessary.
171         */
172        public Object clone() throws CloneNotSupportedException
173        {
174            LdapPrincipal clone = (LdapPrincipal)super.clone();
175            
176            if ( userPassword != null )
177            {
178                clone.setUserPassword( userPassword );
179            }
180            
181            return clone;
182        }
183        
184        
185        /**
186         * @see Externalizable#readExternal(ObjectInput)
187         * 
188         * @param in The stream from which the LdapPrincipal is read
189         * @throws IOException If the stream can't be read
190         * @throws ClassNotFoundException If the LdapPrincipal can't be created 
191         */
192        public void readExternal( ObjectInput in ) throws IOException , ClassNotFoundException
193        {
194            // Read the name
195            name = (DN)in.readObject();
196            
197            // read the authentication level
198            int level = in.readInt();
199            
200            authenticationLevel = AuthenticationLevel.getLevel( level );
201        }
202    
203    
204        /**
205         * @see Externalizable#readExternal(ObjectInput)<p>
206         *
207         *@param out The stream in which the LdapPrincipal will be serialized. 
208         *The password won't be written !
209         *
210         *@throws IOException If the serialization fail
211         */
212        public void writeExternal( ObjectOutput out ) throws IOException
213        {
214            // Write the name
215            if ( name == null )
216            {
217                out.writeObject( DN.EMPTY_DN );
218            }
219            else
220            {
221                out.writeObject( name );
222            }
223            
224            // write the authentication level
225            if ( authenticationLevel == null )
226            {
227                out.writeInt( AuthenticationLevel.NONE.getLevel() );
228            }
229            else
230            {
231                out.writeInt( authenticationLevel.getLevel() );
232            }
233            
234            // and flush the result
235            //out.flush();
236        }
237    }