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 */
020package org.apache.directory.server.kerberos.kdc;
021
022
023import javax.security.auth.kerberos.KerberosPrincipal;
024
025import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
026import org.apache.directory.api.ldap.model.constants.SchemaConstants;
027import org.apache.directory.api.ldap.model.entry.Attribute;
028import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
029import org.apache.directory.api.ldap.model.entry.DefaultModification;
030import org.apache.directory.api.ldap.model.entry.Entry;
031import org.apache.directory.api.ldap.model.entry.Modification;
032import org.apache.directory.api.ldap.model.entry.ModificationOperation;
033import org.apache.directory.api.ldap.model.exception.LdapException;
034import org.apache.directory.api.ldap.model.name.Dn;
035import org.apache.directory.api.ldap.model.schema.SchemaManager;
036import org.apache.directory.api.util.Strings;
037import org.apache.directory.server.constants.ServerDNConstants;
038import org.apache.directory.server.core.api.CoreSession;
039import org.apache.directory.server.core.api.DirectoryService;
040import org.apache.directory.server.core.api.LdapPrincipal;
041import org.apache.directory.server.core.shared.DefaultCoreSession;
042import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
043import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
044import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
045import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
046import org.apache.directory.server.protocol.shared.kerberos.GetPrincipal;
047import org.apache.directory.server.protocol.shared.kerberos.StoreUtils;
048import org.apache.directory.shared.kerberos.KerberosAttribute;
049
050
051/**
052 * A PrincipalStore backing entries in a DirectoryService.
053 * 
054 *
055 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
056 */
057public class DirectoryPrincipalStore implements PrincipalStore
058{
059    /** The directory service backing store for this PrincipalStore. */
060    private final DirectoryService directoryService;
061    private final Dn searchBaseDn;
062
063    private CoreSession adminSession;
064
065
066    /**
067     * Creates a new instance of DirectoryPrincipalStore.
068     *
069     * @param directoryService backing store for this PrincipalStore
070     * @param searchBaseDn The Search Base DN
071     */
072    public DirectoryPrincipalStore( DirectoryService directoryService, Dn searchBaseDn )
073    {
074        this.directoryService = directoryService;
075        this.adminSession = directoryService.getAdminSession();
076        this.searchBaseDn = searchBaseDn;
077    }
078
079
080    /**
081     * {@inheritDoc}
082     */
083    public void changePassword( KerberosPrincipal byPrincipal, KerberosPrincipal forPrincipal, String newPassword,
084        boolean isInitialTicket ) throws ChangePasswordException
085    {
086        try
087        {
088            Entry ebyPrincipalEntry = null;
089
090            ebyPrincipalEntry = StoreUtils.findPrincipalEntry( adminSession, searchBaseDn, byPrincipal.getName() );
091
092            if ( ebyPrincipalEntry == null )
093            {
094                throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_HARDERROR,
095                    Strings.getBytesUtf8( ( "No such principal " + byPrincipal ) ) );
096            }
097
098            SchemaManager schemaManager = directoryService.getSchemaManager();
099
100            CoreSession bySession = null;
101
102            boolean isAdmin = ebyPrincipalEntry.getDn()
103                .equals( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
104
105            if ( !isInitialTicket && !isAdmin )
106            {
107                throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_INITIAL_FLAG_NEEDED );
108            }
109
110            // if admin assign the admin session
111            if ( isAdmin )
112            {
113                bySession = adminSession;
114            }
115            // otherwise create a new session for the user with 'byPrincipal' who is trying to change the password for 'forPrincipal' 
116            else
117            {
118                LdapPrincipal byLdapPrincipal = new LdapPrincipal( schemaManager, ebyPrincipalEntry.getDn(),
119                    AuthenticationLevel.SIMPLE );
120
121                bySession = new DefaultCoreSession( byLdapPrincipal, directoryService );
122            }
123
124            Attribute newPasswordAttribute = new DefaultAttribute(
125                schemaManager.lookupAttributeTypeRegistry( SchemaConstants.USER_PASSWORD_AT ),
126                Strings.getBytesUtf8( newPassword ) );
127            Modification passwordMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
128                newPasswordAttribute );
129
130            Attribute principalAttribute = new DefaultAttribute(
131                schemaManager.lookupAttributeTypeRegistry( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT ),
132                forPrincipal.getName() );
133            Modification principalMod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE,
134                principalAttribute );
135
136            Entry forPrincipalEntry = StoreUtils.findPrincipalEntry( bySession, searchBaseDn, forPrincipal.getName() );
137
138            adminSession.modify( forPrincipalEntry.getDn(), passwordMod, principalMod );
139        }
140        catch ( LdapException e )
141        {
142            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_ACCESSDENIED, e );
143        }
144        catch ( Exception e )
145        {
146            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_HARDERROR, e );
147        }
148    }
149
150
151    /**
152     * {@inheritDoc}
153     */
154    public PrincipalStoreEntry getPrincipal( KerberosPrincipal principal ) throws Exception
155    {
156        return ( PrincipalStoreEntry ) new GetPrincipal( principal ).execute( adminSession, searchBaseDn );
157    }
158}