Статьи

Защищенная JAAS конечная точка JAX-RS

С появлением RESTFUL (JAX-RS) в качестве «предпочтительного» способа создания конечных точек веб-службы, я долгое время всегда задавался вопросом, как люди внедряют механизм безопасности вокруг него.

В конце концов, я предполагаю, что базовой реализацией JAX-RS является сервлет, и, следовательно, его безопасность может также соответствовать тому, что уже предусмотрено контейнером, то есть JAAS.

В этом посте будут представлены мои выводы о том, как поэтапно реализовать безопасность на основе FORM с использованием JDBC-области JAX-RS и как ее протестировать с помощью cURL на Glassfish 3.

Настройка JDBC-царства

Во-первых, поскольку мы используем JDBC-область, давайте предположим, что мы создали соединение JDBC с базовой базой данных в JNDI jdbc/test .

Следующим шагом является создание нового царства. Вы можете сделать это, перейдя в server-config> Security> Realms и добавив новую область. Выберите тип области com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm , а затем заполните обязательные поля.

  • Начните, дав вашему новому царству имя.
  • Для контекста JAAS поместите jdbcRealm
  • Заполните имя JNDI, предпочтительно начинается с "jndi/"

Далее, обратите внимание на остальные поля. Кажется, что Glassfish ожидает увидеть две таблицы. Первая таблица должна содержать список пользователей с именами пользователей в качестве их уникального идентификатора. Вторая таблица — список групп, к которым принадлежит каждый пользователь. Имя пользователя должно быть связью внешнего ключа между двумя таблицами. (Следующий раздел должен дать вам лучшее представление о том, как должны выглядеть таблицы, ведь они очень простые).

После того, как эти таблицы созданы, мы можем заполнить обязательные поля соответственно.

Заполните базу данных для тестирования

Следующим шагом является заполнение таблицы для целей тестирования. Давайте просто предположим, что мы будем тестировать, используя имя пользователя hpotter и пароль test . Однако для пароля обратите внимание, что дайджест Glassfish по умолчанию — SHA-256, как показано на следующем снимке экрана.

SHA-256

Следовательно, вам нужно закодировать test пароля перед вставкой. Вы можете использовать кодировщик от technipixel , который даст вам строку 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 .

Следующим шагом является написание некоторых операторов INSERT:

1
2
3
4
5
INSERT INTO person (id, password, username) VALUES (1, '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', 'hpotter');
COMMIT;
INSERT INTO person_role (username, user_group) VALUES ('hpotter', 'User');
INSERT INTO person_role (username, user_group) VALUES ('hpotter', 'Admin');
COMMIT;

Давайте перейдем к следующему шагу.

Защита веб-приложения с использованием JAAS

На JAAS с методом аутентификации FORM существует множество учебных пособий. Тем не менее, я думал, что поместил это здесь снова, с надеждой, что некоторые могут найти это проще.

web.xml

Сделайте следующую модификацию вашего web.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<welcome-file-list>
        <welcome-file>/index.jsp</welcome-file><!-- 1 -->
    </welcome-file-list>
    <security-constraint><!-- 2 -->
        <display-name>TestConstraint</display-name>
        <web-resource-collection>
            <web-resource-name>TestResource</web-resource-name>
            <description/>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>User</role-name>
            <role-name>Admin</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config><!-- 3 -->
        <auth-method>FORM</auth-method>
        <realm-name>testRealm</realm-name>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/error.html</form-error-page>
        </form-login-config>
    </login-config>
    <security-role><!-- 4 -->
        <description/>
        <role-name>User</role-name>
    </security-role>
    <security-role><!-- 5 -->
        <description/>
        <role-name>Admin</role-name>
    </security-role>

Давайте пройдемся по ним один за другим.

  1. Это файл, который будет отображаться при успешном входе в систему. Вы также можете использовать этот файл в качестве перенаправления. Например, предположим, что у вас есть файл index.xhtml ( index.xhtml JSF), вы можете использовать response.sendRedirect("index.jsf");
  2. Это фактическое ограничение, т.е. как вы защищаете приложение. Этот раздел в основном предназначен для защиты всего доступа к приложению, обозначенного /* url pattern, и разрешает доступ только пользователям с ролью User и Admin .
  3. Эта часть обозначает, что мы используем метод аутентификации FORM (который я объясню более подробно в следующем разделе). Важной частью является обеспечение правильного имени используемой области безопасности, которое в данном случае, testRealm , совпадает с именем области, которое мы дали при настройке через страницу администрирования Glassfish. Другая часть заключается в установке страницы, содержащей j_security_check , на которую приложение будет автоматически перенаправлять в случае, если запрос доступа еще не аутентифицирован.
  4. Известная роль
  5. То же, что и в предыдущем разделе.

GlassFish-web.xml

Нам также нужно настроить glassfish-web.xml чтобы контейнер знал о сопоставлении групп из базы данных и роли, распознаваемой приложением.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
    <security-role-mapping>
        <role-name>Admin</role-name>
        <group-name>Admin</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>User</role-name>
        <group-name>User</group-name>
    </security-role-mapping>
    <class-loader delegate="true"/>
    <jsp-config>
        <property name="keepgenerated" value="true">
            <description>Keep a copy of the generated servlet class' java code.</description>
        </property>
    </jsp-config>
</glassfish-web-app>

NB. Если вы используете Netbeans, этот файл может быть сгенерирован для вас.

Страница входа: login.html

Если мы снова вернемся к web.xml выше, обратите внимание, что страница входа указывает на login.html . Для метода аутентификации FORM, согласно спецификации, нам нужна форма с j_security_check , с j_username и j_password (Oracle 2013).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
    <body>
 
        <form action="j_security_check" method="post">
            <p>
                <strong>Username</strong>
                <input type="text" name="j_username" size="25" />
            </p>
            <p>
                <strong>Password</strong>
                <input type="password" size="15" name="j_password" />
            </p>
            <p>
                <input type="submit" value="Submit" />
                <input type="reset" value="Reset" />
            </p>
        </form>
    </body>
</html>

Завершив все это, мы можем запустить Glassfish, развернуть наше приложение и протестировать его с помощью любого браузера. При доступе к приложению пользователи должны быть направлены на login.html для входа. Не забудьте использовать hpotter качестве имени пользователя и test качестве пароля. При успешном входе в систему пользователь должен быть перенаправлен на index.jsp (который, в свою очередь, перенаправляет пользователя на index.jsf или на что-либо, на index.jsp перенаправляется index.jsp , в соответствии с вашими требованиями).

Создать RESTFUL конечную точку

Следующим шагом, конечно, является создание конечной точки RESTFUL, которая очень проста. Один из постов, которые я написал здесь, также может быть полезен.

Для начала, предполагая, что у нас есть следующий путь к приложению.

01
02
03
04
05
06
07
08
09
10
11
package com.dwuysan;
 
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
/**
 * @author denywuy
 */
@ApplicationPath(value = "resources")
public class ApplicationConfig extends Application {
}

Предположим, что у нас есть следующий простой RESTFUL сервис.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.dwuysan;
 
import com.dwuysan.entity.Outlet;
import com.dwuysan.service.OutletService;
import javax.annotation.ManagedBean;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
 
@Path(value = "generic")
@RolesAllowed(value = "User")
@ManagedBean
public class GenericResource {
 
    @Inject
    private OutletService outletService;
 
    @GET
    @Path("{id}")
    public Outlet get(@PathParam(value = "id") final long id) {
        return this.outletService.getOutlet(id);
    }
}

Обратите внимание, что мы обеспечили этот сервис аннотацией javax.annotation.security.RolesAllowed .

Тестирование защищенного сервиса RESTFUL с использованием curl

Учитывая сервис RESTFUL, который мы создали выше, мы должны иметь возможность протестировать его с помощью CURL с помощью следующей команды:

1
curl -X GET -H "Accept:application/json" -H "Content-Type:application/json" http://localhost:8080/testApp/resources/generic/101

Приведенная выше команда переводит следующее: нажмите URL-адрес выше, используя GET, с заголовками Accept: application / json и Content-Type: application / json (cURL 2013)

Поскольку мы защитили наше приложение, вызов, как указано выше, работать не будет. Пользователь будет перенаправлен на login.html . Следовательно, наша цель сейчас — первый вход в систему. С помощью cURL мы можем отправить параметры для входа в систему, то есть имя пользователя и пароль, а затем получить cookie. Для этого мы можем использовать эту команду:

1
curl -b cookies.txt -c cookies.txt -d "j_username=hpotter&j_password=test" http://localhost:8080/testApp/j_security_check

Эта команда отправляет имя пользователя и пароль в j_security_check (запомните наш login.html который мы создали ранее) и хранит файлы cookie, полученные в файле cookies.txt .

Если вы откроете файл cookies.txt, вы можете увидеть следующее:

1
2
3
4
5
# Netscape HTTP Cookie File
# This file was generated by libcurl! Edit at your own risk.
 
#HttpOnly_localhost     FALSE   /testApp     FALSE   0       JSESSIONID      245a317ab91fbb28244403346770

NB. Вы можете получить ответ «Перемещение документа» Это означает, что вход был успешным. В противном случае вы получите снова необработанный html error.html .

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

1
curl -X GET -H "Accept:application/json" -H "Content-Type:application/json" -b cookies.txt -c cookies.txt http://localhost:8080/testApp/resources/generic/101

Рекомендации: