Статьи

Безопасность веб-приложений на Java — часть III: демонстрация входа в Apache Shiro

Пару недель назад я написал учебник о том, как реализовать безопасность с помощью Spring Security . За неделю до этого я написал аналогичное руководство для Java EE 6 . На этой неделе я хотел бы показать вам, как реализовать те же функции с помощью Apache Shiro . Как я упоминал в предыдущих статьях, я пишу это, потому что я сказал аудитории в апреле UJUG, что я буду публиковать скриншоты демонстраций.

Сегодня я закончил третий скринкаст, показывающий, как реализовать безопасность с помощью Apache Shiro. Ниже представлена ​​презентация (с включенной на слайде 22 скринкастом), а также пошаговое руководство.

Apache Shiro Войти Учебник

Загрузите и запустите приложение.
Для начала загрузите приложение, в котором вы будете внедрять систему безопасности. Это приложение является урезанной версией приложения Ajax Login, которое я написал для своей статьи о реализации Ajax-аутентификации с использованием jQuery, Spring Security и HTTPS . Для запуска приложения вам потребуется Java 6 и Maven. Запустите его, используя mvn jetty: run и откройте http: // localhost: 8080 в вашем браузере. Вы увидите, что это простое приложение CRUD для пользователей, и для добавления или удаления пользователей не требуется вход в систему.

Реализация базовой аутентификации
Первым шагом является защита экрана списка, чтобы людям приходилось входить в систему для просмотра пользователей. Для этого вам нужно создать файл Shiro.ini для конфигурации Shiro. Создайте src / main / resources / shiro.ini и заполните его содержимым ниже:

[main]

[users]
admin = admin, ROLE_ADMIN

[roles]
ROLE_ADMIN = *

[urls]
/app/users = authcBasic

Вы можете видеть, что этот файл имеет четыре раздела и довольно прост для чтения и понимания. Для получения дополнительной информации о том, для чего предназначен каждый раздел, ознакомьтесь с документацией по конфигурации Shiro .

Затем откройте src / main / webapp / WEB-INF / web.xml и добавьте IniShiroFilter Широ:

<filter>
<filter-name>securityFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>
<!-- no init-param means load the INI config from classpath:shiro.ini -->
</filter>

И добавьте его сопоставление фильтра сразу после rewriteFilter в разделе сопоставления фильтра (порядок важен!):

<filter-mapping>
<filter-name>rewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>securityFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>

Затем добавьте основные и веб- зависимости Широ в ваш pom.xml:

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.1.0</version>
</dependency>

На этом этапе, если вы перезапустите Jetty (Ctrl + C и Jetty: запустите снова), вам будет предложено войти в систему, когда вы нажмете на вкладку «Пользователи». Введите admin / admin для входа. Apache Shiro проще в настройке, чем Spring Security, в основном потому, что для него не требуется XML.

После входа в систему вы можете попытаться выйти, нажав ссылку «Выйти» в правом верхнем углу. Это вызывает LogoutController со следующим кодом, который выводит пользователя из системы.

public void logout(HttpServletResponse response) throws ServletException, IOException {
request.getSession().invalidate();
response.sendRedirect(request.getContextPath());
}

ПРИМЕЧАНИЕ. В настоящее время у Shiro нет способа выхода из системы с помощью API. Тем не менее, он будет добавлен в версии 1.2 .

Вы заметите, что щелкнув по этой ссылке, вы не выйдете из системы, даже если сеанс признан недействительным. Единственный способ выйти из системы с базовой аутентификацией — закрыть браузер. Чтобы получить возможность выхода из системы, а также получить больший контроль над внешним видом входа в систему, вы можете реализовать аутентификацию на основе форм. Перед тем, как вы внедрите аутентификацию на основе форм, я хотел бы показать вам, как легко использовать SSL с Apache Shiro.

Принудительное использование SSL
Apache Shiro позволяет принудительно использовать SSL для URL-адреса, просто добавив «ssl [ порт ]» к URL-адресу в разделе [urls]. Если вы не укажете порт, он будет использовать порт по умолчанию (443). Я не уверен, позволяет ли он вам переключиться обратно на http, как требует канал безопасности Spring Spring , но я не думаю, что это так. Измените раздел URL вашего shiro.ini, чтобы иметь следующее:

[urls]
/app/users = ssl[8443],authc

Чтобы это работало, вы должны настроить Jetty на прослушивание порта SSL. Добавьте следующее сразу после элемента </ webAppConfig> для jetty-maven-plugin в вашем файле pom.xml:

<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<forwarded>true</forwarded>
<port>8080</port>
</connector>
<connector implementation="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
<forwarded>true</forwarded>
<port>8443</port>
<maxIdleTime>60000</maxIdleTime>
<keystore>${project.build.directory}/ssl.keystore</keystore>
<password>appfuse</password>
<keyPassword>appfuse</keyPassword>
</connector>
</connectors>

Хранилище ключей должно быть сгенерировано для успешного запуска Jetty, поэтому добавьте keytool-maven-plugin чуть выше jetty-maven-plugin в pom.xml.

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>keytool-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<id>clean</id>
<goals>
<goal>clean</goal>
</goals>
</execution>
<execution>
<phase>generate-resources</phase>
<id>genkey</id>
<goals>
<goal>genkey</goal>
</goals>
</execution>
</executions>
<configuration>
<keystore>${project.build.directory}/ssl.keystore</keystore>
<dname>cn=localhost</dname>
<keypass>appfuse</keypass>
<storepass>appfuse</storepass>
<alias>appfuse</alias>
<keyalg>RSA</keyalg>
</configuration>
</plugin>

Теперь, если вы перезапустите Jetty, перейдите по адресу http: // localhost: 8080 и перейдите на вкладку «Пользователи», вам будет предложено принять ненадежный сертификат, а затем после входа будет перенаправлен на https: // localhost: 8443 / users ,

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

Реализация аутентификации на основе форм
Чтобы перейти от базовой аутентификации на основе форм, вам просто нужно добавить несколько строк в shiro.ini. Прежде всего, поскольку я бы не хотел менять имя элементов ввода в login.jsp, переопределите имена по умолчанию в разделе [main]:

# name of request parameter with username; if not present filter assumes 'username'
authc.usernameParam = j_username
# name of request parameter with password; if not present filter assumes 'password'
authc.passwordParam = j_password
authc.failureKeyAttribute = shiroLoginFailure

Затем измените раздел [urls] для фильтрации на login.jsp и используйте «authc» вместо «authcBasic»:

[urls]
# The /login.jsp is not restricted to authenticated users (otherwise no one could log in!), but
# the 'authc' filter must still be specified for it so it can process that url's
# login submissions. It is 'smart' enough to allow those requests through as specified by the
# shiro.loginUrl above.
/login.jsp = authc
/app/users = ssl[8443],authc

Затем измените login.jsp так, чтобы действие формы было пустым (что приводило к его отправке на себя) вместо j_security_check:

1.
<form action="" id="loginForm" method="post">

Теперь перезапустите Jetty, и вам будет предложено войти в систему с помощью этого JSP вместо обычного диалога аутентификации.

Хранение пользователей в базе данных
Чтобы хранить пользователей в базе данных, а не в файле, вам нужно добавить несколько параметров в shiro.ini, чтобы определить базу данных и таблицы для использования. Откройте src / main / resources / shiro.ini и добавьте следующие строки в раздел [main].

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#jdbcRealm.permissionsLookupEnabled=false
# If not filled, subclasses of JdbcRealm assume "select password from users where username = ?"
jdbcRealm.authenticationQuery = select user_pass from users where user_name = ?
# If not filled, subclasses of JdbcRealm assume "select role_name from user_roles where username = ?"
jdbcRealm.userRolesQuery = select role_name from users_roles where user_name = ?

ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.databaseName = appfuse
jdbcRealm.dataSource = $ds

Эта конфигурация аналогична той, что я делал в учебном руководстве по Java EE 6, где я указываю на базу данных, отличную от экземпляра H2, который используется приложением. Я полагаю, что Широ может общаться с DAO, как Spring Security, но мне еще предстоит изучить этот вариант.

Пока вы это делаете, добавьте следующие строки, чтобы включить шифрование пароля.

sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
jdbcRealm.credentialsMatcher = $sha256Matcher

Вам нужно будет установить MySQL, чтобы это работало. После его установки вы сможете создать базу данных appfuse с помощью следующей команды:

mysql -u root -p -e 'create database appfuse'

Затем создайте необходимые таблицы и заполните их пользователем «admin». Войдите в систему с помощью «mysql -u root -p appfuse» и выполните следующие операторы SQL:

create table users (
  user_name         varchar(30) not null primary key,
  user_pass         varchar(100) not null
);

create table user_roles (
  user_name         varchar(30) not null,
  role_name         varchar(30) not null,
  primary key (user_name, role_name)
);

insert into users values ('admin', '22f256eca1f336a97eef2b260773cb0d81d900c208ff26e94410d292d605fed8');
insert into user_roles values ('admin', 'ROLE_ADMIN');

Теперь, если вы перезапустите Jetty, вы сможете войти с помощью admin / adminjdbc и просмотреть список пользователей.

Резюме
В этом руководстве вы узнали, как реализовать аутентификацию с использованием Apache Shiro 1.1.0. У меня нет большого опыта работы с Apache Shiro, но я смог заставить работать основы без особых усилий. Этот урок не показывает, как сделать «Помни меня», потому что я не смог понять это за 5 минут, а это значит, что у меня есть еще 5 минут, прежде чем он провалит 10-минутный тест.;)

Широ ранее назывался JSecurity и был проектом Apache менее года. Похоже, что он в большей степени ориентирован на не-веб-использование, поэтому на него, безусловно, стоит обратить внимание, если вы больше заинтересованы в криптографии или не-веб-приложениях. Я думаю, что есть хороший шанс, что этот проект будет продолжать расти и использоваться больше, поскольку все больше разработчиков узнают об этом. Бренд Apache определенно не повредит.

Я не включил слайд об ограничениях, которые я нашел с Широ, главным образом потому, что я не использовал это много. Я использовал Java EE и Spring Security в течение нескольких лет. Основным ограничением, которое я обнаружил, было отсутствие документации, но я слышал, что она быстро улучшается.

Это знаменует конец этой серии по реализации безопасности в веб-приложениях Java. Я представлю эту тему в Jazoon, а также полную версию (со взломом) на ÜberConf . Надеюсь, увидимся на одной из этих конференций.

От http://raibledesigns.com/rd/entry/java_web_application_security_part2