All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.mina.proxy.handlers.http.digest.HttpDigestAuthLogicHandler Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.mina.proxy.handlers.http.digest;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.mina.core.filterchain.IoFilter.NextFilter;
import org.apache.mina.proxy.ProxyAuthException;
import org.apache.mina.proxy.handlers.http.AbstractAuthLogicHandler;
import org.apache.mina.proxy.handlers.http.HttpProxyConstants;
import org.apache.mina.proxy.handlers.http.HttpProxyRequest;
import org.apache.mina.proxy.handlers.http.HttpProxyResponse;
import org.apache.mina.proxy.session.ProxyIoSession;
import org.apache.mina.proxy.utils.StringUtilities;
import org.apache.mina.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HttpDigestAuthLogicHandler.java - HTTP Digest authentication mechanism logic handler.
*
* @author Apache MINA Project
* @since MINA 2.0.0-M3
*/
public class HttpDigestAuthLogicHandler extends AbstractAuthLogicHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpDigestAuthLogicHandler.class);
/**
* The challenge directives provided by the server.
*/
private Map directives = null;
/**
* The response received to the last request.
*/
private HttpProxyResponse response;
private static SecureRandom rnd;
static {
// Initialize secure random generator
try {
rnd = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* Creates a new HttpDigestAuthLogicHandler instance
*
* @param proxyIoSession The Proxy IoSession
* @throws ProxyAuthException The Proxy AuthException
*/
public HttpDigestAuthLogicHandler(ProxyIoSession proxyIoSession) throws ProxyAuthException {
super(proxyIoSession);
((HttpProxyRequest) request).checkRequiredProperties(HttpProxyConstants.USER_PROPERTY,
HttpProxyConstants.PWD_PROPERTY);
}
/**
* {@inheritDoc}
*/
@Override
public void doHandshake(NextFilter nextFilter) throws ProxyAuthException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(" doHandshake()");
}
if (step > 0 && directives == null) {
throw new ProxyAuthException("Authentication challenge not received");
}
HttpProxyRequest req = (HttpProxyRequest) request;
Map> headers = req.getHeaders() != null ? req.getHeaders()
: new HashMap>();
if (step > 0) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(" sending DIGEST challenge response");
}
// Build a challenge response
HashMap map = new HashMap<>();
map.put("username", req.getProperties().get(HttpProxyConstants.USER_PROPERTY));
StringUtilities.copyDirective(directives, map, "realm");
StringUtilities.copyDirective(directives, map, "uri");
StringUtilities.copyDirective(directives, map, "opaque");
StringUtilities.copyDirective(directives, map, "nonce");
String algorithm = StringUtilities.copyDirective(directives, map, "algorithm");
// Check for a supported algorithm
if (algorithm != null && !"md5".equalsIgnoreCase(algorithm) && !"md5-sess".equalsIgnoreCase(algorithm)) {
throw new ProxyAuthException("Unknown algorithm required by server");
}
// Check for a supported qop
String qop = directives.get("qop");
if (qop != null) {
StringTokenizer st = new StringTokenizer(qop, ",");
String token = null;
while (st.hasMoreTokens()) {
String tk = st.nextToken();
if ("auth".equalsIgnoreCase(token)) {
break;
}
int pos = Arrays.binarySearch(DigestUtilities.SUPPORTED_QOPS, tk);
if (pos > -1) {
token = tk;
}
}
if (token != null) {
map.put("qop", token);
byte[] nonce = new byte[8];
rnd.nextBytes(nonce);
try {
String cnonce = new String(Base64.encodeBase64(nonce), proxyIoSession.getCharsetName());
map.put("cnonce", cnonce);
} catch (UnsupportedEncodingException e) {
throw new ProxyAuthException("Unable to encode cnonce", e);
}
} else {
throw new ProxyAuthException("No supported qop option available");
}
}
map.put("nc", "00000001");
map.put("uri", req.getHttpURI());
// Compute the response
try {
map.put("response", DigestUtilities.computeResponseValue(proxyIoSession.getSession(), map, req
.getHttpVerb().toUpperCase(), req.getProperties().get(HttpProxyConstants.PWD_PROPERTY),
proxyIoSession.getCharsetName(), response.getBody()));
} catch (Exception e) {
throw new ProxyAuthException("Digest response computing failed", e);
}
// Prepare the challenge response header and add it to the
// request we will send
StringBuilder sb = new StringBuilder("Digest ");
boolean addSeparator = false;
for ( Map.Entry entry : map.entrySet()) {
String key = entry.getKey();
if (addSeparator) {
sb.append(", ");
} else {
addSeparator = true;
}
boolean quotedValue = !"qop".equals(key) && !"nc".equals(key);
sb.append(key);
if (quotedValue) {
sb.append("=\"").append(entry.getValue()).append('\"');
} else {
sb.append('=').append(entry.getValue());
}
}
StringUtilities.addValueToHeader(headers, "Proxy-Authorization", sb.toString(), true);
}
addKeepAliveHeaders(headers);
req.setHeaders(headers);
writeRequest(nextFilter, req);
step++;
}
@Override
public void handleResponse(final HttpProxyResponse response) throws ProxyAuthException {
this.response = response;
if (step == 0) {
if (response.getStatusCode() != 401 && response.getStatusCode() != 407) {
throw new ProxyAuthException("Received unexpected response code (" + response.getStatusLine() + ").");
}
// Header should look like this
// Proxy-Authenticate: Digest still_some_more_stuff
List values = response.getHeaders().get("Proxy-Authenticate");
String challengeResponse = null;
for (String s : values) {
if (s.startsWith("Digest")) {
challengeResponse = s;
break;
}
}
if (challengeResponse == null) {
throw new ProxyAuthException("Server doesn't support digest authentication method !");
}
try {
directives = StringUtilities.parseDirectives(challengeResponse.substring(7).getBytes(
proxyIoSession.getCharsetName()));
} catch (Exception e) {
throw new ProxyAuthException("Parsing of server digest directives failed", e);
}
step = 1;
} else {
throw new ProxyAuthException("Received unexpected response code (" + response.getStatusLine() + ").");
}
}
}