/** * This format supports Shared Key authentication for the 2009-09-19 version of the Blob and Queue * services. Construct the CanonicalizedResource string in this format as follows: * * <p>1. Beginning with an empty string (""), append a forward slash (/), followed by the name of * the account that owns the resource being accessed. * * <p>2. Append the resource's encoded URI path, without any query parameters. * * <p>3. Retrieve all query parameters on the resource URI, including the comp parameter if it * exists. * * <p>4. Convert all parameter names to lowercase. * * <p>5. Sort the query parameters lexicographically by parameter name, in ascending order. * * <p>6. URL-decode each query parameter name and value. * * <p>7. Append each query parameter name and value to the string in the following format, making * sure to include the colon (:) between the name and the value: * * <p>parameter-name:parameter-value * * <p>8. If a query parameter has more than one value, sort all values lexicographically, then * include them in a comma-separated list: * * <p>parameter-name:parameter-value-1,parameter-value-2,parameter-value-n * * <p>9. Append a new line character (\n) after each name-value pair. */ private String getCanonicalizedResource(ClientRequest cr) { // 1. Beginning with an empty string (""), append a forward slash (/), followed by the name of // the account that owns // the resource being accessed. String result = "/" + this.accountName; // 2. Append the resource's encoded URI path, without any query parameters. result += cr.getURI().getPath(); // 3. Retrieve all query parameters on the resource URI, including the comp parameter if it // exists. // 6. URL-decode each query parameter name and value. List<QueryParam> queryParams = SharedKeyUtils.getQueryParams(cr.getURI().getQuery()); // 4. Convert all parameter names to lowercase. for (QueryParam param : queryParams) { param.setName(param.getName().toLowerCase(Locale.US)); } // 5. Sort the query parameters lexicographically by parameter name, in ascending order. Collections.sort(queryParams); // 7. Append each query parameter name and value to the string // 8. If a query parameter has more than one value, sort all values lexicographically, then // include them in a comma-separated list for (int i = 0; i < queryParams.size(); i++) { QueryParam param = queryParams.get(i); List<String> values = param.getValues(); // Collections.sort(values); // 9. Append a new line character (\n) after each name-value pair. result += "\n"; result += param.getName(); result += ":"; for (int j = 0; j < values.size(); j++) { if (j > 0) { result += ","; } result += values.get(j); } } return result; }
private Request buildRequest(ClientRequest req) throws IOException { final Request request = client.newRequest(req.getURI()).method(HttpMethod.fromString(req.getMethod())); if (req.getEntity() != null) { final RequestEntityWriter writer = getRequestEntityWriter(req); final PipedOutputStream output = new PipedOutputStream(); final PipedInputStream input = new PipedInputStream(output); request.content(new InputStreamContentProvider(input)); writer.writeRequestEntity(output); } return request; }
public ClientResponse handle(ClientRequest clientRequest) { byte[] requestEntity = writeRequestEntity(clientRequest); InBoundHeaders rh = getInBoundHeaders(clientRequest.getMetadata()); final ContainerRequest cRequest = new ContainerRequest( w, clientRequest.getMethod(), baseUri, clientRequest.getURI(), rh, new ByteArrayInputStream(requestEntity)); // TODO this is a hack List<String> cookies = cRequest.getRequestHeaders().get("Cookie"); if (cookies != null) { for (String cookie : cookies) { if (cookie != null) cRequest.getCookies().putAll(HttpHeaderReader.readCookies(cookie)); } } final TstContainerResponseWriter writer = new TstContainerResponseWriter(); final ContainerResponse cResponse = new ContainerResponse(w, cRequest, writer); try { w.handleRequest(cRequest, cResponse); } catch (IOException e) { throw new ContainerException(e); } byte[] responseEntity = writer.baos.toByteArray(); ClientResponse clientResponse = new ClientResponse( cResponse.getStatus(), getInBoundHeaders(cResponse.getHttpHeaders()), new ByteArrayInputStream(responseEntity), getMessageBodyWorkers()); clientResponse.getProperties().put("request.entity", requestEntity); clientResponse.getProperties().put("response.entity", responseEntity); return clientResponse; }
private ClientResponse _invoke(final ClientRequest ro) throws IOException { final HttpURLConnection uc; if (this.httpURLConnectionFactory == null) { uc = (HttpURLConnection) ro.getURI().toURL().openConnection(); } else { uc = this.httpURLConnectionFactory.getHttpURLConnection(ro.getURI().toURL()); } Integer readTimeout = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_READ_TIMEOUT); if (readTimeout != null) { uc.setReadTimeout(readTimeout); } Integer connectTimeout = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_CONNECT_TIMEOUT); if (connectTimeout != null) { uc.setConnectTimeout(connectTimeout); } Boolean followRedirects = (Boolean) ro.getProperties().get(ClientConfig.PROPERTY_FOLLOW_REDIRECTS); if (followRedirects != null) { uc.setInstanceFollowRedirects(followRedirects); } if (uc instanceof HttpsURLConnection) { HTTPSProperties httpsProperties = (HTTPSProperties) ro.getProperties().get(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES); if (httpsProperties != null) { httpsProperties.setConnection((HttpsURLConnection) uc); } } Boolean httpUrlConnectionSetMethodWorkaround = (Boolean) ro.getProperties().get(PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND); if (httpUrlConnectionSetMethodWorkaround != null && httpUrlConnectionSetMethodWorkaround == true) { setRequestMethodUsingWorkaroundForJREBug(uc, ro.getMethod()); } else { uc.setRequestMethod(ro.getMethod()); } // Write the request headers writeOutBoundHeaders(ro.getHeaders(), uc); // Write the entity (if any) Object entity = ro.getEntity(); if (entity != null) { uc.setDoOutput(true); if (ro.getMethod().equalsIgnoreCase("GET")) { final Logger logger = Logger.getLogger(URLConnectionClientHandler.class.getName()); if (logger.isLoggable(Level.INFO)) { logger.log( Level.INFO, "GET method with entity will be most likely replaced by POST, see http://java.net/jira/browse/JERSEY-1161"); } } writeRequestEntity( ro, new RequestEntityWriterListener() { public void onRequestEntitySize(long size) { if (size != -1 && size < Integer.MAX_VALUE) { // HttpURLConnection uses the int type for content length uc.setFixedLengthStreamingMode((int) size); } else { // TODO it appears HttpURLConnection has some bugs in // chunked encoding // uc.setChunkedStreamingMode(0); Integer chunkedEncodingSize = (Integer) ro.getProperties().get(ClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE); if (chunkedEncodingSize != null) { uc.setChunkedStreamingMode(chunkedEncodingSize); } } } public OutputStream onGetOutputStream() throws IOException { return new CommittingOutputStream() { @Override protected OutputStream getOutputStream() throws IOException { return uc.getOutputStream(); } @Override public void commit() throws IOException { writeOutBoundHeaders(ro.getHeaders(), uc); } }; } }); } else { writeOutBoundHeaders(ro.getHeaders(), uc); } // Return the in-bound response return new URLConnectionResponse( uc.getResponseCode(), getInBoundHeaders(uc), getInputStream(uc), ro.getMethod(), uc); }
@Override public ClientResponse handle(final ClientRequest request) throws ClientHandlerException { // Remember if we sent a request a with headers boolean reqHadAuthHeaders = false; // Have we already login ? : Then add authorization info to the headers if (state.get().nextNonce != null) { // Remember we sent headers reqHadAuthHeaders = true; // Alias to string representation of qop String qopStr = null; if (state.get().qop != null) qopStr = (state.get().qop == QOP.AUTH_INT) ? "auth-int" : "auth"; // Init the value of the "authorized" header StringBuffer buff = new StringBuffer(); // Authorization scheme buff.append("Digest "); // Key/val pairs addKeyVal(buff, "username", this.user); addKeyVal(buff, "realm", state.get().realm); addKeyVal(buff, "nonce", state.get().nextNonce); if (state.get().opaque != null) addKeyVal(buff, "opaque", state.get().opaque); if (state.get().algorithm != null) addKeyVal(buff, "algorithm", state.get().algorithm, false); if (state.get().qop != null) addKeyVal(buff, "qop", qopStr, false); // if (this.domain != null) addKeyVal(buff, "domain", this.domain); // ------------------------------------------------------- // Compute the Digest Hash // ------------------------------------------------------- // HA1 String HA1 = concatMD5(this.user, state.get().realm, this.pass); // Get exact requested URI String uri = request.getURI().getPath(); // Repeat URI in header addKeyVal(buff, "uri", uri); // HA2 : Switch on qop String HA2; if (state.get().qop == QOP.AUTH_INT && (request.getEntity() != null)) { HA2 = concatMD5(request.getMethod(), uri, request.getEntity().toString()); } else { HA2 = concatMD5(request.getMethod(), uri); } // Compute response String response; if (state.get().qop == null) { // Simple response response = concatMD5(HA1, state.get().nextNonce, HA2); } else { // Quality of protection is set // Generate client nonce (UID) String cnonce = randHexBytes(CNONCE_NB_BYTES); // Counter in hexadecimal String nc = String.format("%08x", state.get().counter); state.get().counter += 1; // Add them to key/value pairs addKeyVal(buff, "cnonce", cnonce); addKeyVal(buff, "nc", nc, false); response = concatMD5(HA1, state.get().nextNonce, nc, cnonce, qopStr, HA2); } // Append the response addKeyVal(buff, "response", response); // Remove the last coma buff.deleteCharAt(buff.length() - 1); String authLine = buff.toString(); // Add the whole Authorization line to the header request.getMetadata().add(HttpHeaders.AUTHORIZATION, authLine); } // End of "we already logged in ?" // Forward the request to the next filter and get the result back ClientResponse response = getNext().handle(request); // The server asked for authentication ? (status 401) if (response.getResponseStatus() == Status.UNAUTHORIZED) { // Parse the www-authentication headers HashMap<String, String> map = parseHeaders(response.getHeaders().get(HttpHeaders.WWW_AUTHENTICATE)); // No digest authentication request found ? => We can do nothing more if (map == null) return response; // Get header values state.get().realm = map.get("realm"); state.get().nextNonce = map.get("nonce"); state.get().opaque = map.get("opaque"); state.get().algorithm = map.get("algorithm"); state.get().domain = map.get("domain"); // Parse Qop String qop = map.get("qop"); if (qop == null) { state.get().qop = null; } else { if (qop.contains("auth-int")) { state.get().qop = QOP.AUTH_INT; } else if (qop.contains("auth")) { state.get().qop = QOP.AUTH; } else { state.get().qop = null; } } // Parse "stale" String staleStr = map.get("stale"); boolean stale = (staleStr != null) && staleStr.toLowerCase().equals("true"); // Did we send the initial request without headers ? // Or the server asked to retry with new nonce ? if (stale || !reqHadAuthHeaders) { // Then try to resent same request with updated headers return this.handle(request); } else { // We already tried to log, but the authentication failed : // Just forward this response return response; } } // Not 401 status : no authentication issue return response; } // End of #handle()