001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027package org.apache.http.impl.auth;
028
029import java.nio.charset.Charset;
030
031import org.apache.commons.codec.binary.Base64;
032import org.apache.http.Consts;
033import org.apache.http.Header;
034import org.apache.http.HttpRequest;
035import org.apache.http.auth.AUTH;
036import org.apache.http.auth.AuthenticationException;
037import org.apache.http.auth.ChallengeState;
038import org.apache.http.auth.Credentials;
039import org.apache.http.auth.MalformedChallengeException;
040import org.apache.http.message.BufferedHeader;
041import org.apache.http.protocol.BasicHttpContext;
042import org.apache.http.protocol.HttpContext;
043import org.apache.http.util.Args;
044import org.apache.http.util.CharArrayBuffer;
045import org.apache.http.util.EncodingUtils;
046
047/**
048 * Basic authentication scheme as defined in RFC 2617.
049 *
050 * @since 4.0
051 */
052public class BasicScheme extends RFC2617Scheme {
053
054    private static final long serialVersionUID = -1931571557597830536L;
055
056    /** Whether the basic authentication process is complete */
057    private boolean complete;
058
059    /**
060     * @since 4.3
061     */
062    public BasicScheme(final Charset credentialsCharset) {
063        super(credentialsCharset);
064        this.complete = false;
065    }
066
067    /**
068     * Creates an instance of {@code BasicScheme} with the given challenge
069     * state.
070     *
071     * @since 4.2
072     *
073     * @deprecated (4.3) do not use.
074     */
075    @Deprecated
076    public BasicScheme(final ChallengeState challengeState) {
077        super(challengeState);
078    }
079
080    public BasicScheme() {
081        this(Consts.ASCII);
082    }
083
084    /**
085     * Returns textual designation of the basic authentication scheme.
086     *
087     * @return {@code basic}
088     */
089    @Override
090    public String getSchemeName() {
091        return "basic";
092    }
093
094    /**
095     * Processes the Basic challenge.
096     *
097     * @param header the challenge header
098     *
099     * @throws MalformedChallengeException is thrown if the authentication challenge
100     * is malformed
101     */
102    @Override
103    public void processChallenge(
104            final Header header) throws MalformedChallengeException {
105        super.processChallenge(header);
106        this.complete = true;
107    }
108
109    /**
110     * Tests if the Basic authentication process has been completed.
111     *
112     * @return {@code true} if Basic authorization has been processed,
113     *   {@code false} otherwise.
114     */
115    @Override
116    public boolean isComplete() {
117        return this.complete;
118    }
119
120    /**
121     * Returns {@code false}. Basic authentication scheme is request based.
122     *
123     * @return {@code false}.
124     */
125    @Override
126    public boolean isConnectionBased() {
127        return false;
128    }
129
130    /**
131     * @deprecated (4.2) Use {@link org.apache.http.auth.ContextAwareAuthScheme#authenticate(
132     *   Credentials, HttpRequest, org.apache.http.protocol.HttpContext)}
133     */
134    @Override
135    @Deprecated
136    public Header authenticate(
137            final Credentials credentials, final HttpRequest request) throws AuthenticationException {
138        return authenticate(credentials, request, new BasicHttpContext());
139    }
140
141    /**
142     * Produces basic authorization header for the given set of {@link Credentials}.
143     *
144     * @param credentials The set of credentials to be used for authentication
145     * @param request The request being authenticated
146     * @throws org.apache.http.auth.InvalidCredentialsException if authentication
147     *   credentials are not valid or not applicable for this authentication scheme
148     * @throws AuthenticationException if authorization string cannot
149     *   be generated due to an authentication failure
150     *
151     * @return a basic authorization string
152     */
153    @Override
154    public Header authenticate(
155            final Credentials credentials,
156            final HttpRequest request,
157            final HttpContext context) throws AuthenticationException {
158
159        Args.notNull(credentials, "Credentials");
160        Args.notNull(request, "HTTP request");
161        final StringBuilder tmp = new StringBuilder();
162        tmp.append(credentials.getUserPrincipal().getName());
163        tmp.append(":");
164        tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
165
166        final Base64 base64codec = new Base64(0);
167        final byte[] base64password = base64codec.encode(
168                EncodingUtils.getBytes(tmp.toString(), getCredentialsCharset(request)));
169
170        final CharArrayBuffer buffer = new CharArrayBuffer(32);
171        if (isProxy()) {
172            buffer.append(AUTH.PROXY_AUTH_RESP);
173        } else {
174            buffer.append(AUTH.WWW_AUTH_RESP);
175        }
176        buffer.append(": Basic ");
177        buffer.append(base64password, 0, base64password.length);
178
179        return new BufferedHeader(buffer);
180    }
181
182    /**
183     * Returns a basic {@code Authorization} header value for the given
184     * {@link Credentials} and charset.
185     *
186     * @param credentials The credentials to encode.
187     * @param charset The charset to use for encoding the credentials
188     *
189     * @return a basic authorization header
190     *
191     * @deprecated (4.3) use {@link #authenticate(Credentials, HttpRequest, HttpContext)}.
192     */
193    @Deprecated
194    public static Header authenticate(
195            final Credentials credentials,
196            final String charset,
197            final boolean proxy) {
198        Args.notNull(credentials, "Credentials");
199        Args.notNull(charset, "charset");
200
201        final StringBuilder tmp = new StringBuilder();
202        tmp.append(credentials.getUserPrincipal().getName());
203        tmp.append(":");
204        tmp.append((credentials.getPassword() == null) ? "null" : credentials.getPassword());
205
206        final byte[] base64password = Base64.encodeBase64(
207                EncodingUtils.getBytes(tmp.toString(), charset), false);
208
209        final CharArrayBuffer buffer = new CharArrayBuffer(32);
210        if (proxy) {
211            buffer.append(AUTH.PROXY_AUTH_RESP);
212        } else {
213            buffer.append(AUTH.WWW_AUTH_RESP);
214        }
215        buffer.append(": Basic ");
216        buffer.append(base64password, 0, base64password.length);
217
218        return new BufferedHeader(buffer);
219    }
220
221    @Override
222    public String toString() {
223        final StringBuilder builder = new StringBuilder();
224        builder.append("BASIC [complete=").append(complete)
225                .append("]");
226        return builder.toString();
227    }
228}