View Javadoc
1   /**
2    * Copyright (c) 2012-2015, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.odesk;
31  
32  import com.jcabi.aspects.Immutable;
33  import com.jcabi.http.Request;
34  import com.jcabi.http.Response;
35  import com.jcabi.http.Wire;
36  import com.jcabi.immutable.Array;
37  import com.jcabi.log.Logger;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.net.URLDecoder;
41  import java.util.AbstractMap;
42  import java.util.Collection;
43  import java.util.Map;
44  import java.util.logging.Level;
45  import javax.ws.rs.core.HttpHeaders;
46  import lombok.EqualsAndHashCode;
47  import lombok.ToString;
48  import org.scribe.builder.ServiceBuilder;
49  import org.scribe.builder.api.DefaultApi10a;
50  import org.scribe.model.OAuthRequest;
51  import org.scribe.model.Token;
52  import org.scribe.model.Verb;
53  import org.scribe.oauth.OAuthService;
54  
55  /**
56   * OAuth Wire.
57   *
58   * @author Yegor Bugayenko (yegor@tpc2.com)
59   * @version $Id: 6ce5bed47ba193556f50f986589b31f04b69fd51 $
60   * @since 0.1
61   */
62  @Immutable
63  @ToString
64  @EqualsAndHashCode(of = { "origin", "key", "secret", "token", "tsecret" })
65  public final class OAuthWire implements Wire {
66  
67      /**
68       * Original wire.
69       */
70      private final transient Wire origin;
71  
72      /**
73       * Application key.
74       */
75      private final transient String key;
76  
77      /**
78       * Application secret.
79       */
80      private final transient String secret;
81  
82      /**
83       * Access token.
84       */
85      private final transient String token;
86  
87      /**
88       * Access token secret.
89       */
90      private final transient String tsecret;
91  
92      /**
93       * Public ctor.
94       * @param wire Original wire
95       * @param akey App key
96       * @param scrt App secret
97       * @param tkn OAuth access token
98       * @param tscrt OAuth access token secret part
99       * @checkstyle ParameterNumber (10 lines)
100      */
101     public OAuthWire(final Wire wire, final String akey, final String scrt,
102         final String tkn, final String tscrt) {
103         this.origin = wire;
104         this.key = akey;
105         this.secret = scrt;
106         this.token = tkn;
107         this.tsecret = tscrt;
108     }
109 
110     // @checkstyle ParameterNumber (10 lines)
111     @Override
112     public Response send(final Request req, final String home,
113         final String method,
114         final Collection<Map.Entry<String, String>> headers,
115         final InputStream content, final int connect, final int read)
116         throws IOException {
117         final OAuthService service = new ServiceBuilder()
118             .provider(OAuthWire.OdeskApi.class)
119             .apiKey(this.key)
120             .apiSecret(this.secret)
121             .debugStream(Logger.stream(Level.FINE, this))
122             .build();
123         final String[] parts = home.split("\\?", 2);
124         final OAuthRequest oauth = new OAuthRequest(
125             Verb.valueOf(method), parts[0]
126         );
127         if (parts.length == 2) {
128             for (final String pair : parts[1].split("&")) {
129                 final String[] eqn = pair.split("=", 2);
130                 final String value;
131                 if (eqn.length == 2) {
132                     value = URLDecoder.decode(eqn[1], "UTF-8");
133                 } else {
134                     value = "";
135                 }
136                 oauth.addQuerystringParameter(eqn[0], value);
137             }
138         }
139         service.signRequest(new Token(this.token, this.tsecret), oauth);
140         return this.origin.send(
141             req, oauth.getCompleteUrl(), method,
142             new Array<Map.Entry<String, String>>(headers).with(
143                 new AbstractMap.SimpleEntry<String, String>(
144                     HttpHeaders.AUTHORIZATION,
145                     oauth.getHeaders().get(HttpHeaders.AUTHORIZATION)
146                 )
147             ),
148             content,
149             connect, read
150         );
151     }
152 
153     /**
154      * Odesk provider.
155      * @link https://github.com/fernandezpablo85/scribe-java/pull/438
156      */
157     public static final class OdeskApi extends DefaultApi10a {
158         @Override
159         public String getAccessTokenEndpoint() {
160             return "https://www.odesk.com/api/auth/v1/oauth/token/access";
161         }
162         @Override
163         public String getAuthorizationUrl(final Token tkn) {
164             return String.format(
165                 "https://www.odesk.com/services/api/auth?oauth_token=%s",
166                 tkn.getToken()
167             );
168         }
169         @Override
170         public String getRequestTokenEndpoint() {
171             return "https://www.odesk.com/api/auth/v1/oauth/token/request";
172         }
173     }
174 
175 }