Обычная проверка подлинности в REST-приложении

Окружающая среда:

  • JAVA
  • Glassfish
  • REST-сервисы на разных машинах.
  • HTML5-клиент с AJAX и JQuery
  • Джерси

Это то, что я реализовал до сих пор:

HTML5-клиент ###

$('#btnSignIn').click(function () {
    var username = $("#username").val();
    var password = $("#password").val();

    function make_base_auth(user, password) {
        var tok = user + ':' + password;

        var final = "Basic " + $.base64.encode(tok);
        console.log("FINAL---->" + final);
        alert("FINAL---->" + final);

        return final;
    }

    $.ajax({
        type: "GET",
        contentType: "application/json",
        url: "http://localhost:8080/SesameService/webresources/users/secured/login",
        crossDomain: true,
        dataType: "text",
        async: false,
        data: {},
        beforeSend: function (xhr) {
            xhr.setRequestHeader('authorization', make_base_auth(username, password));
        },
        success: function () {
            alert('Thanks for your signin in! ');

        },
        error: function (jqXHR, textStatus, errorThrown) {
            console.log(textStatus, errorThrown);
            alert(' Error in signIn-process!! ' + textStatus);
        }
    });
});

SERVER

В разделе "Безопасность" у меня нет диспетчера безопасности, он отключен!

Я настроил BASIC-аутентификацию на Glassfish, и мой web.xml выглядит следующим образом:

<servlet-mapping>
    <servlet-name>ServletAdaptor</servlet-name>
    <url-pattern>/webresources/*</url-pattern>
</servlet-mapping>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>REST Protected resources</web-resource-name>
        <description/>
        <url-pattern>/users/*</url-pattern>

    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>customer</role-name>
        <role-name>user</role-name>
    </auth-constraint>
</security-constraint>



<login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>jdbcRealm</realm-name>
    </login-config>
    <security-role>
        <role-name>admin</role-name>
    </security-role>
    <security-role>
        <role-name>user</role-name>
    </security-role>
    <security-role>
        <description/>
        <role-name>customer</role-name>
    </security-role>

GlassFish

enter image description here

LOG

FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/users/secured/login" "GET")
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
FINE: [Web-Security] hasResource isGranted: true
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/users/secured/login" "GET")

Вопрос:

  • Если я шифрую (НЕ кодирую) пароль в клиенте, когда пользователь регистрируется и передает его под SSL/HTTPS, является ли этот безопасный и хороший способ реализовать это?

  • Если я использую REST-сервис без клиента, он всегда открыт, ПОЧЕМУ? Нет BASIC-аутентификации? Я понял что-то не так с этими шаблонами url?

    http://localhost:8080/SesameService/webresources/users/secured/login
    
  • ЕСЛИ я получу эту работу, как проверить это, потому что теперь, если я аутентифицирую один раз, я всегда уполномочен? Возможно ли "выйти из системы" программно внутри REST-сервиса или вообще как реализовать выход из системы?

  • При использовании авторизации в заголовке с обязательным именем пользователя с кодировкой base64: пароль должен ли я также закодировать свое имя пользователя и пароль для БД? Я попробовал это и добавил Encoding (допустимые значения Hex и Base64) в jdbcRealm в Glassfish, и кажется, что пароля достаточно, но что происходит, когда оба закодированы на клиенте?

ОБНОВЛЕНИЕ: Я изменил web.xml и теперь BASIC-аутентификация работает при вызове REST-сервиса прямо в браузере: http://localhost:8080/SesameService/users/secured/login

Изменения:

  • Я включил менеджера безопасности в Glassfish
  • Я изменил шаблон url

          ServletAdaptor       /* ---- > Я снял webresources. Он был создан Netbeans    

  • Я изменил URL-адрес для обслуживания: http://localhost:8080/SesameService/users/secured/login

Теперь я получаю HTTP/1.1 401 Unauthorized при попытке аутентификации с HTML5-клиента.

Заголовки запроса: `

Origin: http://localhost:8383
Host:`localhost:8080`
Connection:keep-alive
Access-Control-Request-Method:GET
Access-Control-Request-Headers:authorization,content-type`

Ответ:

x-powered-by:Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.2.2 Java/Oracle Corporation/1.7)
WWW-Authenticate:Basic realm="jdbcRealm"
Server:GlassFish Server Open Source Edition 3.1.2.2
Pragma:No-cache
Expires:Thu, 01 Jan 1970 02:00:00 EET
Date:Sat, 13 Apr 2013 15:25:06 GMT
Content-Type:text/html
Content-Length:1073
Cache-Control:no-cache

ОБНОВЛЕНИЕ 2

Когда я пытаюсь выполнить аутентификацию с помощью JavaScript + Заголовок авторизации, я получил ошибку 401 и что в журнале:

FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/users/secured/login" "OPTIONS")
FINE: [Web-Security] hasUserDataPermission isGranted: true---->!!!!!!!!!!!!!
FINE: [Web-Security] Policy Context ID was: SesameService/SesameService
FINE: [Web-Security] Codesource with Web URL: file:/SesameService/SesameService
FINE: [Web-Security] Checking Web Permission with Principals : null------->!!!!!!!
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
FINEST: JACC Policy Provider: PolicyWrapper.implies, context (SesameService/SesameService)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS"))
FINE: [Web-Security] hasResource isGranted: false------->!!!!!!!!!
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")
FINEST: JACC Policy Provider: PolicyWrapper.getPermissions(cs), context (null) codesource ((null <no signer certificates>)) permissions: [email protected] (

**** ОБНОВЛЕНИЕ 3 **** Я не могу быть первым и единственным человеком, который пытается аутентифицироваться с использованием BASIC в случае с кросс-доменом. Я сменил фильтры своего креста: response.getHttpHeaders(). putSingle ( "Access-Control-Allow-Headers", "Авторизация" );

Ошибка NO 401, но все еще ошибка в JavaScript. IN Журнал Glassfish:

FINEST: JACC Policy Provider:
getPolicy (SesameService/SesameService) is NOT in service----->!!!!!!!!
FINE: JACC Policy Provider: file arrival check type: granted  arrived: false exists: false lastModified: 0 storedTime: 1365968416000 state: deleted SesameService/SesameService
FINE: JACC Policy Provider: file arrival check type: excluded  arrived: false exists: false lastModified: 0 storedTime: 0 state: deleted SesameService/SesameService
FINE: TM: getTransaction: tx=null, tm=null
FINE: TM: [email protected]7fe9a8
FINE: TM: resourceTable before: 0
FINE: TM: resourceTable after: 0

Кстати, потому что я никогда не получаю эту работу, делает это так же, как вызов REST-сервиса прямо в своем собственном домене. Итак, открывается первый клиентский запрос, запросы сервера и имя пользователя-пароля, затем запрос клиента и сервер аутентифицируются и отвечают на эту страницу? Я пытаюсь его получить: запрос с заголовком авторизации в нем, ответ от сервера с результатом службы останова и его. Любая идея, как обеспечить REST-услуги? Легче этого? Это невозможно.

ОБНОВЛЕНИЕ 4

Я просто попытался переместить моего HTML5-клиента в веб-проект java, только чистые html-страницы и в том же домене, а BASIC-аутентификация работает на 100%. Поэтому причина кросс-доменная среда.

Ответы

Ответ 1

Если я шифрую (НЕ кодирую) пароль в клиенте, когда пользователь регистрируется и передает его под SSL/HTTPS, является ли это безопасным и хорошим способом реализовать это?

Скорее всего, вы должны просто передать пароль в виде простого текста через SSL/HTTPS.

Вся связь в SSL/HTTPS зашифровывается, поэтому, вероятно, не рекомендуется также шифровать пароль, если вам не нужно гарантировать, что веб-сервер (технически терминатор HTTPS) не сможет увидеть пароль.

Если я использую REST-сервис без клиента, он всегда открыт, ПОЧЕМУ? Нет BASIC-аутентификации? Я понял что-то не так с этими шаблонами url?

Не уверен, что я понимаю вопрос. Однако BASIC auth не является хорошим шаблоном для аутентификации в REST, поскольку он передает пароль в виде обычного текста.

ЕСЛИ я получу эту работу, как проверить это, потому что теперь, если я аутентифицирую один раз, я всегда уполномочен? Возможно ли "выйти из системы" программно внутри REST-сервиса или вообще как реализовать выход из системы?

В Basic Auth имя пользователя и пароль передаются клиентом в каждом HTTP-запросе. Если учетные данные не передаются клиентом, сервер отклоняет запрос. Как таковой нет понятия сеанса.

Однако, что касается сервера Java EE, логин создает сеанс пользователя, и будущие запросы того же пользователя будут использовать один и тот же сеанс. Если вы его сконфигурируете, этот сеанс будет отсутствовать.

Если выходить из строя важно (например, управлять сеансами пользователя), вам необходимо создать сервлет (/logout) для этого, который отменяет сеанс HTTP.

Стандартная модель безопасности Java работает следующим образом: Когда пользователь входит в систему безопасности, сервер Java EE хранит безопасный файл cookie в вашем браузере. Браузер отправляет этот файл cookie обратно на сервер Java EE в каждом запросе в той же области. Сервер Java EE проверяет этот файл cookie в каждом запросе и использует его для идентификации пользователя, подключая запрос к сеансу пользователя.

Таким образом, вы, вероятно, захотите сделать службу REST в той же области безопасности, что и веб-приложение, поэтому браузер и сервер работают без проблем.

При использовании авторизации в заголовке с обязательным именем пользователя с кодировкой base64: пароль должен ли я также кодировать свое имя пользователя и пароль для БД? Я попробовал это и добавил Encoding (допустимые значения Hex и Base64) в jdbcRealm в Glassfish, и кажется, что пароля достаточно, но что происходит, когда оба закодированы на клиенте?

Нет, не кодируйте имя пользователя или пароль - все это обрабатывается глубоко в браузере и Glassfish. Если вы кодируете на клиенте, клиент будет кодировать кодировку, и сервер отклонит пароль.


Не могли бы вы рассказать мне, можно ли использовать j_security_check с html5-страницы с javaScript или снова в проблемах:) Я создал пару файлов Primefaces + jsf-application, где я использовал FORM-auth, и не было никаких проблема, но для меня это было катастрофой.

Вы должны уметь комфортно работать с j_security_check, полагая, что службы RESTful остаются в одном домене и области безопасности (тогда вход в веб-приложение позволит браузеру отправить правильный файл cookie в URI REST).

Обратите внимание, однако, что другим приложениям будет трудно получить доступ к службам REST. В основном, они должны будут войти в систему через j_security_check, а затем сохранить файлы cookie, отправленные Glassfish. Если вам понадобятся другие приложения для доступа к этим службам программно, вам понадобится другое решение:

  • Вы можете настроить область безопасности, чтобы позволить другим аутентификаторам быть "достаточными"; настройте HTTP BASIC Auth и убедитесь, что ни один из них не помечен как "необходимый"
  • Разверните службы RESTful дважды, а другой - другой URI. Если вы хотите использовать HTTP BASIC Auth, это может быть конечная точка SSL/HTTPS, чтобы обеспечить надежную обработку паролей.

Ответ 2



Я работаю над Spring инфраструктурой MVC с помощью Spring безопасности и использую базовую аутентификацию:

В основном, при базовой аутентификации HTTP имя пользователя и пароль преобразуются в ключ или токен доступа с помощью класса Base64 (из пакета util).

И этот ключ устанавливается в заголовок URL-адреса HTTP, а затем попадает на сервер.

Он отлично работает и на сервере: декодирует ключ пароля имени пользователя одним и тем же Base64, а затем совпадает с именем пользователя и паролем базы данных. если аутентификация завершена, то дальнейший процесс.

Это обеспечивает безопасность API-адресов. У каждого органа нет доступа.

код: Создать токен доступа (ключ):

ПРИМЕЧАНИЕ. Мы передаем строку в Base64 (из пакета util) "YourUsername: YourPassword" для кодирования.
Да, имя пользователя и пароль разделены ":".

        String encodeddata = new String(Base64.encodeBase64("username:password".getBytes()));
        System.out.println("encodedBytes " + encodeddata);

Код для установки ключа в заголовок:

//ЗАПРОС НА URL С КЛЮЧОМ

        HttpClient client = HttpClientBuilder.create().build();
        HttpGet get = new HttpGet("http://google.com/Abc/api/vou/redeemed");
        get.setHeader("Authorization", "Basic "+encodeddata); //key getting above

Примечание. Вы можете использовать это с помощью метода Get и Post. Здесь я использую только метод get. //RESPONSE

        HttpResponse jresponse = client.execute(get);

        System.out.println("Response Code : "+ jresponse.getStatusLine().getStatusCode());

        BufferedReader rd = new BufferedReader(new InputStreamReader(jresponse.getEntity().getContent()));

        StringBuffer result = new StringBuffer();
        String line = "";
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }

        System.out.println("------Response is ::: "+ result);

//DECODE Key

        String usernameAndPassword = null;
        try {
            usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword));
        } catch (Exception e) {
            System.out.println("SERVER_ERROR");
        }
        System.out.println(usernameAndPassword);

        final StringTokenizer tokenizer = new StringTokenizer(encodedUserPassword, ":");
        final String username = tokenizer.nextToken();
        final String password = tokenizer.nextToken();

        System.out.println(username);
        System.out.println(password);