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.ldap;
021
022
023import org.apache.commons.lang3.StringUtils;
024import org.apache.directory.api.ldap.model.csn.Csn;
025import org.apache.directory.api.ldap.model.message.Request;
026import org.apache.directory.api.ldap.model.message.Response;
027import org.apache.directory.api.util.Strings;
028import org.apache.directory.server.core.api.interceptor.context.OperationContext;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031
032
033/**
034 * Utility methods used by the LDAP protocol service.
035 *
036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037 */
038public final class LdapProtocolUtils
039{
040    /** A delimiter for the replicaId */
041    public static final String COOKIE_DELIM = ",";
042
043    /** the prefix for replicaId value */
044    public static final String REPLICA_ID_PREFIX = "rid=";
045
046    public static final int REPLICA_ID_PREFIX_LEN = REPLICA_ID_PREFIX.length();
047
048    /** the prefix for Csn value */
049    public static final String CSN_PREFIX = "csn=";
050
051    private static final int CSN_PREFIX_LEN = CSN_PREFIX.length();
052
053    private static final Logger LOG = LoggerFactory.getLogger( LdapProtocolUtils.class );
054
055
056    private LdapProtocolUtils()
057    {
058    }
059
060
061    /**
062     * Extracts request controls from a request to populate into an
063     * OperationContext.
064     *
065     * @param opContext the context to populate with request controls
066     * @param request the request to extract controls from
067     */
068    public static void setRequestControls( OperationContext opContext, Request request )
069    {
070        if ( request.getControls() != null )
071        {
072            opContext
073                .addRequestControls( request.getControls().values().toArray( LdapProtocolConstants.EMPTY_CONTROLS ) );
074        }
075    }
076
077
078    /**
079     * Extracts response controls from a an OperationContext to populate into
080     * a Response object.
081     *
082     * @param opContext the context to extract controls from
083     * @param response the response to populate with response controls
084     */
085    public static void setResponseControls( OperationContext opContext, Response response )
086    {
087        response.addAllControls( opContext.getResponseControls() );
088    }
089
090
091    public static byte[] createCookie( int replicaId, String csn )
092    {
093        // the syncrepl cookie format (compatible with OpenLDAP)
094        // rid=nn,csn=xxxz
095        String replicaIdStr = StringUtils.leftPad( Integer.toString( replicaId ), 3, '0' );
096        return Strings.getBytesUtf8( REPLICA_ID_PREFIX + replicaIdStr + COOKIE_DELIM + CSN_PREFIX + csn );
097    }
098
099
100    /**
101     * Check the cookie syntax. A cookie must have the following syntax :
102     * { rid={replicaId},csn={CSN} }
103     *
104     * @param cookieString The cookie
105     * @return <tt>true</tt> if the cookie is valid
106     */
107    public static boolean isValidCookie( String cookieString )
108    {
109        if ( ( cookieString == null ) || ( cookieString.trim().length() == 0 ) )
110        {
111            return false;
112        }
113
114        int pos = cookieString.indexOf( COOKIE_DELIM );
115
116        // position should start from REPLICA_ID_PREFIX_LEN or higher cause a cookie can be
117        // like "rid=0,csn={csn}" or "rid=11,csn={csn}"
118        if ( pos <= REPLICA_ID_PREFIX_LEN )
119        {
120            return false;
121        }
122
123        String replicaId = cookieString.substring( REPLICA_ID_PREFIX_LEN, pos );
124
125        try
126        {
127            Integer.parseInt( replicaId );
128        }
129        catch ( NumberFormatException e )
130        {
131            LOG.debug( "Failed to parse the replica id {}", replicaId );
132            return false;
133        }
134
135        if ( pos == cookieString.length() )
136        {
137            return false;
138        }
139
140        String csnString = cookieString.substring( pos + 1 + CSN_PREFIX_LEN );
141
142        return Csn.isValid( csnString );
143    }
144
145
146    /**
147     * returns the CSN present in cookie
148     *
149     * @param cookieString the cookie
150     * @return The CSN
151     */
152    public static String getCsn( String cookieString )
153    {
154        int pos = cookieString.indexOf( COOKIE_DELIM );
155        return cookieString.substring( pos + 1 + CSN_PREFIX_LEN );
156    }
157
158
159    /**
160     * returns the replica id present in cookie
161     *
162     * @param cookieString  the cookie
163     * @return The replica Id
164     */
165    public static int getReplicaId( String cookieString )
166    {
167        String replicaId = cookieString.substring( REPLICA_ID_PREFIX_LEN, cookieString.indexOf( COOKIE_DELIM ) );
168
169        return Integer.parseInt( replicaId );
170    }
171}