Дайджест-аутентификация с помощью Jersey Client

Я написал веб-службу REST с сервером Jersey Server (это просто потрясающе!). Сейчас я разрабатываю клиентскую часть, в том числе с помощью Jersey Client.

На стороне сервера я выбрал аутентификацию DIGEST, потому что лично я считаю, что BASIC аутентификация — это ересь, которая должна быть помечена как «УСТАРЕВШАЯ» в наших головах.

К сожалению, я не вижу поддержки дайджест-аутентификации на стороне клиента. Для аутентификации BASIC можно сделать что-то вроде:

client.addFilter(
    new HTTPBasicAuthFilter(
        user, 
        password));

Но я не вижу аналога "HTTPDigestAuthFilter". Я что-то пропустил ?

Спасибо за вашу помощь,

Рафаэль


person Raphael Jolivet    schedule 02.06.2010    source источник
comment
Хорошо, я спросил в списке рассылки Джерси, и в настоящее время его не существует. Так что реализую. Я опубликую его там, как только он заработает.   -  person Raphael Jolivet    schedule 09.06.2010
comment
Пожалуйста, следите за ходом работы в соответствующей ветке списка рассылки Джерси на Nabble: jersey.576304.n2.nabble.com/   -  person Raphael Jolivet    schedule 14.06.2010
comment
Почему базовая HTTP-аутентификация доступа должна быть объявлена ​​устаревшей?   -  person user359996    schedule 04.11.2010
comment
Потому что пароли не зашифрованы и любой посредник может их увидеть/записать.   -  person Raphael Jolivet    schedule 05.11.2010
comment
Базовая аутентификация доступа не претендует на шифрование трафика, так что это не недостаток. На самом деле, это хорошее разделение задач: используйте базовую аутентификацию доступа для аутентификации и TLS для шифрования. Дополнительная сложность дайджест-аутентификации нужна только в том случае, если 1) зашифрованный транспорт невозможен и 2) полезная нагрузка сообщения не нуждается в шифровании. Если последнее не так, необходим зашифрованный транспорт, и дайджест-аутентификация просто становится дополнительным и ненужным бременем по сравнению с простотой базовой аутентификации доступа. Разные инструменты для разных нужд.   -  person user359996    schedule 07.11.2010
comment
Спасибо за добавление в пример HTTPBasicAuthFilter, это было именно то, что мне было нужно. Basic Auth подходит для моих нужд, и я нигде не смог найти пример!   -  person Dick Chesterwood    schedule 19.03.2011


Ответы (2)


Я только что реализовал это. Я создал запрос функции в системе отслеживания проблем Джерси и разместил там свою реализацию в виде вложения: https://jersey.dev.java.net/issues/show_bug.cgi?id=542

Он отлично работает для связи с DIGEST-аутентификацией сервера Tomcat. Я еще не тестировал для других веб-серверов.

person Raphael Jolivet    schedule 24.06.2010
comment
+1 Самостоятельная реализация отсутствующей функциональности и ее выпуск. - person user359996; 17.12.2010

Здесь я написал какой-то случайный uri. Пожалуйста, заполните желаемый URI

Для пробного тестирования вы можете воспользоваться помощью сервисов Google, которые доступны в Интернете для открытого доступа.

    import javax.ws.rs.core.*;
    import org.apache.commons.codec.digest.*;
    import org.codehaus.jettison.json.*;
    import com.sun.jersey.api.*;


    public class DigestClient {

    //Dividing into two parts because we need to send the last part of uri in our second request to service.
    static String baseUri = "https://www.something.com";
    static String subUri = "/later-part";

    public static void main(String[] args) throws JSONException{

        ClientConfig cc = new DefaultClientConfig();
        Client client = Client.create(cc);

        WebResource webResource = client.resource(baseUri+subUri);
        ClientResponse response = webResource.get(ClientResponse.class);
        // Basically in Digest-Authentication mechanism, we hit the rest service two times. 
        // First time with No Authentication, which returns some values (qop, nonce, realm) which are used as inputs in second call to rest service.


        /*--------------- First call-----------------*/
        // We get 401, Unauthorized
        System.out.println(response.getStatus()+"   "+response.getStatusInfo());
        // Here is the complete header information
        System.out.println(response.getHeaders());
        // We need "WWW-Authenticate" part information for our second call to rest
        System.out.println("WWW-Authenticate: \t" + response.getHeaders().get("www-Authenticate"));


        String noAuthResp = response.getHeaders().get("www-Authenticate").toString();
        noAuthResp = noAuthResp.replace("Digest ", "");
        noAuthResp = noAuthResp.replace('[', '{');
        noAuthResp = noAuthResp.replace(']', '}');

        // Creating a JSONObject for easy information retrieval 
        JSONObject resp = new JSONObject(noAuthResp);


        /*--------------- Second call-----------------*/
        // Here client has to set the fields which was returned from the first call
        String user = "postman";          // username
        String password = "password";          // password
        String realm = resp.getString("realm");          // realm value from the first rest-call response
        String qop = resp.getString("qop");          //qop value from the first rest-call response
        String nonce = resp.getString("nonce");          // nonce value from the first rest-call response
        String opaque = resp.getString("opaque");          // Some times if we don't get this value, set it with ""
        String algorithm = "MD5";          // The algorithm set by the  client
        int nonceCount = 678;          // Some numerical input from the client
        String clientNonce = "afdjas0";          // Some random text from the client for encryption

        String method = "GET";          // HTTP method

        String ha1 = new DigestClient().formHA1(user, realm, password);
        String ha2 = new DigestClient().formHA2(method, subUri);
        String responseCode =  new DigestClient().generateResponse(ha1, nonce, nonceCount, clientNonce, qop, ha2);

        // Header to be sent to the service
        String value = "Digest username=\""+user+"\", realm=\""+realm+"\", nonce=\""+nonce+"\", uri=\""+subUri+"\", qop="+qop+", nc="+nonceCount+", cnonce=\""+clientNonce+"\", response=\""+responseCode+"\", opaque=\""+opaque+"\"";          

        // Hitting the service
        response = webResource.header("authorization", value).type(MediaType.TEXT_PLAIN).accept("*").get(ClientResponse.class);
        System.out.println("\nComplete Response:\n"+response+"\n");
        String output = response.getEntity(String.class);
        System.out.println("Response Text: "+output);
    }

    // For generating HA1 value
    public String formHA1(String userName,String realm,String password){
        String ha1 = DigestUtils.md5Hex(userName + ":" + realm + ":" + password);
        return ha1;
    }
    // For generating HA2 value
    public String formHA2(String method,String uri){
        String ha2=DigestUtils.md5Hex(method + ":" + uri);
        return ha2;
    }

    // For generating response at client side
    public String generateResponse(String ha1,String nonce,int nonceCount,String clientNonce,String qop,String ha2){
        String response=DigestUtils.md5Hex(ha1 + ":" + nonce + ":" + nonceCount + ":" +clientNonce +":" + qop + ":" +ha2);
        return response;

    }
    }
person G r s s vinay    schedule 05.01.2017