1/*
2 * Copyright (C) 2013 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.squareup.okhttp;
17
18import java.io.IOException;
19import java.io.UnsupportedEncodingException;
20import java.net.Proxy;
21import java.net.URL;
22import java.util.List;
23import okio.ByteString;
24
25/**
26 * Responds to authentication challenges from the remote web or proxy server by
27 * returning credentials.
28 */
29public interface OkAuthenticator {
30  /**
31   * Returns a credential that satisfies the authentication challenge made by
32   * {@code url}. Returns null if the challenge cannot be satisfied. This method
33   * is called in response to an HTTP 401 unauthorized status code sent by the
34   * origin server.
35   *
36   * @param challenges parsed "WWW-Authenticate" challenge headers from the HTTP
37   *     response.
38   */
39  Credential authenticate(Proxy proxy, URL url, List<Challenge> challenges) throws IOException;
40
41  /**
42   * Returns a credential that satisfies the authentication challenge made by
43   * {@code proxy}. Returns null if the challenge cannot be satisfied. This
44   * method is called in response to an HTTP 401 unauthorized status code sent
45   * by the proxy server.
46   *
47   * @param challenges parsed "Proxy-Authenticate" challenge headers from the
48   *     HTTP response.
49   */
50  Credential authenticateProxy(Proxy proxy, URL url, List<Challenge> challenges) throws IOException;
51
52  /** An RFC 2617 challenge. */
53  public final class Challenge {
54    private final String scheme;
55    private final String realm;
56
57    public Challenge(String scheme, String realm) {
58      this.scheme = scheme;
59      this.realm = realm;
60    }
61
62    /** Returns the authentication scheme, like {@code Basic}. */
63    public String getScheme() {
64      return scheme;
65    }
66
67    /** Returns the protection space. */
68    public String getRealm() {
69      return realm;
70    }
71
72    @Override public boolean equals(Object o) {
73      return o instanceof Challenge
74          && ((Challenge) o).scheme.equals(scheme)
75          && ((Challenge) o).realm.equals(realm);
76    }
77
78    @Override public int hashCode() {
79      return scheme.hashCode() + 31 * realm.hashCode();
80    }
81
82    @Override public String toString() {
83      return scheme + " realm=\"" + realm + "\"";
84    }
85  }
86
87  /** An RFC 2617 credential. */
88  public final class Credential {
89    private final String headerValue;
90
91    private Credential(String headerValue) {
92      this.headerValue = headerValue;
93    }
94
95    /** Returns an auth credential for the Basic scheme. */
96    public static Credential basic(String userName, String password) {
97      try {
98        String usernameAndPassword = userName + ":" + password;
99        byte[] bytes = usernameAndPassword.getBytes("ISO-8859-1");
100        String encoded = ByteString.of(bytes).base64();
101        return new Credential("Basic " + encoded);
102      } catch (UnsupportedEncodingException e) {
103        throw new AssertionError();
104      }
105    }
106
107    public String getHeaderValue() {
108      return headerValue;
109    }
110
111    @Override public boolean equals(Object o) {
112      return o instanceof Credential && ((Credential) o).headerValue.equals(headerValue);
113    }
114
115    @Override public int hashCode() {
116      return headerValue.hashCode();
117    }
118
119    @Override public String toString() {
120      return headerValue;
121    }
122  }
123}
124