001package com.pusher.client.util; 002 003import com.pusher.client.AuthorizationFailureException; 004import com.pusher.client.Authorizer; 005import java.io.BufferedReader; 006import java.io.DataOutputStream; 007import java.io.IOException; 008import java.io.InputStream; 009import java.io.InputStreamReader; 010import java.net.HttpURLConnection; 011import java.net.MalformedURLException; 012import java.net.URL; 013import java.util.HashMap; 014import java.util.Map; 015import javax.net.ssl.HttpsURLConnection; 016 017/** 018 * Used to authenticate a {@link com.pusher.client.channel.PrivateChannel 019 * private} or {@link com.pusher.client.channel.PresenceChannel presence} 020 * channel subscription. 021 * 022 * <p> 023 * Makes an HTTP request to a defined HTTP endpoint. Expects an authentication 024 * token to be returned. 025 * </p> 026 * 027 * <p> 028 * For more information see the <a 029 * href="http://pusher.com/docs/authenticating_users">Authenticating Users 030 * documentation</a>. 031 */ 032public class HttpAuthorizer implements Authorizer { 033 034 private final URL endPoint; 035 private Map<String, String> mHeaders = new HashMap<String, String>(); 036 private ConnectionFactory mConnectionFactory = null; 037 038 /** 039 * Creates a new authorizer. 040 * 041 * @param endPoint 042 * The endpoint to be called when authenticating. 043 */ 044 public HttpAuthorizer(final String endPoint) { 045 try { 046 this.endPoint = new URL(endPoint); 047 this.mConnectionFactory = new UrlEncodedConnectionFactory(); 048 } 049 catch (final MalformedURLException e) { 050 throw new IllegalArgumentException("Could not parse authentication end point into a valid URL", e); 051 } 052 } 053 054 /** 055 * Creates a new authorizer. 056 * 057 * @param endPoint The endpoint to be called when authenticating. 058 * @param connectionFactory a custom connection factory to be used for building the connection 059 */ 060 public HttpAuthorizer(final String endPoint, final ConnectionFactory connectionFactory) { 061 try { 062 this.endPoint = new URL(endPoint); 063 this.mConnectionFactory = connectionFactory; 064 } catch (final MalformedURLException e) { 065 throw new IllegalArgumentException("Could not parse authentication end point into a valid URL", e); 066 } 067 } 068 069 /** 070 * Set additional headers to be sent as part of the request. 071 * 072 * @param headers A map of headers 073 */ 074 public void setHeaders(final Map<String, String> headers) { 075 mHeaders = headers; 076 } 077 078 /** 079 * Identifies if the HTTP request will be sent over HTTPS. 080 * @return true if the endpoint protocol is 'https' 081 */ 082 public Boolean isSSL() { 083 return endPoint.getProtocol().equals("https"); 084 } 085 086 @Override 087 public String authorize(final String channelName, final String socketId) throws AuthorizationFailureException { 088 try { 089 mConnectionFactory.setChannelName(channelName); 090 mConnectionFactory.setSocketId(socketId); 091 String body = mConnectionFactory.getBody(); 092 093 final HashMap<String, String> defaultHeaders = new HashMap<String, String>(); 094 defaultHeaders.put("Content-Type", mConnectionFactory.getContentType()); 095 defaultHeaders.put("charset", mConnectionFactory.getCharset()); 096 097 HttpURLConnection connection; 098 if (isSSL()) { 099 connection = (HttpsURLConnection)endPoint.openConnection(); 100 } 101 else { 102 connection = (HttpURLConnection)endPoint.openConnection(); 103 } 104 connection.setDoOutput(true); 105 connection.setDoInput(true); 106 connection.setInstanceFollowRedirects(false); 107 connection.setRequestMethod("POST"); 108 109 // Add in the user defined headers 110 defaultHeaders.putAll(mHeaders); 111 // Add in the Content-Length, so it can't be overwritten by mHeaders 112 defaultHeaders.put("Content-Length","" + Integer.toString(body.getBytes().length)); 113 114 for (final String headerName : defaultHeaders.keySet()) { 115 final String headerValue = defaultHeaders.get(headerName); 116 connection.setRequestProperty(headerName, headerValue); 117 } 118 119 connection.setUseCaches(false); 120 121 // Send request 122 final DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); 123 wr.writeBytes(body); 124 wr.flush(); 125 wr.close(); 126 127 // Read response 128 final InputStream is = connection.getInputStream(); 129 final BufferedReader rd = new BufferedReader(new InputStreamReader(is)); 130 String line; 131 final StringBuffer response = new StringBuffer(); 132 while ((line = rd.readLine()) != null) { 133 response.append(line); 134 } 135 rd.close(); 136 137 final int responseHttpStatus = connection.getResponseCode(); 138 if (responseHttpStatus != 200 && responseHttpStatus != 201) { 139 throw new AuthorizationFailureException(response.toString()); 140 } 141 142 return response.toString(); 143 144 } 145 catch (final IOException e) { 146 throw new AuthorizationFailureException(e); 147 } 148 } 149}