#sql #authentication #tomcat #jdbcrealm
#sql #аутентификация #tomcat #jdbcrealm
Вопрос:
У меня есть досадная ошибка, которую я не могу решить довольно долго. Недавно я познакомился с безопасностью на основе контейнеров и попытался ее реализовать. Я настроил область следующим образом:
<Realm className="org.apache.catalina.realm.JDBCRealm"
debug="99"
driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/identify"
connectionName="adm" connectionPassword="pw"
userTable="users" userNameCol="login"
userCredCol="password"
allRolesMode="authOnly" />
</Realm>
К сожалению, я не могу войти в систему с помощью этого. Сообщения об ошибках журнала:
SEVERE: Exception performing authentication
java.sql.SQLException: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version
for the right syntax to use near 'null WHERE login = 'user1'' at line 1
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2928)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1571)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1666)
at com.mysql.jdbc.Connection.execSQL(Connection.java:2994)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:936)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1030)
at org.apache.catalina.realm.JDBCRealm.getRoles(JDBCRealm.java:640)
at org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:430)
at org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:355)
at org.apache.catalina.realm.CombinedRealm.authenticate(CombinedRealm.java:146)
at org.apache.catalina.realm.LockOutRealm.authenticate(LockOutRealm.java:180)
at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:282)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:440)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:851)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:278)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:636)
Пожалуйста, обратите внимание на » вокруг имени пользователя… Это правильно?
Как вы видите, я также использую allRolesMode="authOnly"
, потому что мне не нужна эта функциональность, и, кроме того, в базе данных нет и никогда не будет дополнительного столбца для пользовательских ролей (это совершенно бессмысленно, если не использовать его, тогда каждый пользователь будет иметь одинаковое значение в этом столбце — большая трата ресурсов.).
Сервер — Tomcat 7.0.19
Ответ №1:
Вы должны установить свойства userRoleTable
and roleNameCol
в случае allRolesMode="authOnly"
too . Без них SQL-запрос будет содержать строку null
(как вы можете видеть в сообщении об исключении). Значение userRoleTable
может совпадать со значением userTable
, а roleNameCol
также может совпадать с userNameCol
.
Простым обходным путем является создание представления SQL, которое эмулирует roles
таблицу:
CREATE VIEW roles (username, role)
AS SELECT username, 'user' FROM users;
И решение:
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://127.0.0.1:3306/test"
connectionName="..." connectionPassword="..."
userTable="users" userNameCol="username" userCredCol="password"
userRoleTable="users" roleNameCol="username"
/>
(На удивление, это работает без каких-либо allRolesMode
.)
Требуемые web.xml
фрагменты:
<security-constraint>
<web-resource-collection>
<web-resource-name>protected zone</web-resource-name>
<url-pattern>/prot/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>*</role-name>
</security-role>
(Примечание: допустим, у вас 1 миллион пользователей, новый атрибут в users
таблице с одним миллионом user
строк будет стоить всего около 5 мегабайт. Я согласен с тем, что это не красивое решение, но в наши дни оно не является невыносимо большим.)
Комментарии:
1. Спасибо. Я пытаюсь убедить администратора базы данных в конце концов добавить этот столбец роли пользователя, но если мои переговоры не сработают, я попробую ваш подход. Однако на самом деле глупо, что у tomcat есть такое ограничение :/ Я имею в виду — иногда вы можете не иметь никакого влияния на построение БД, и тогда вы облажались: / Простая функция = большие проблемы…
2. «И решение» работает без каких-либо изменений схемы базы данных, и есть несколько других подходов: написание пользовательского
JDBCRealm
интерфейса (Tomcat с открытым исходным кодом, поэтому вы можете изменить существующий), реализация пользовательскогоValve
интерфейса, который добавляет роль к участнику пользователя. Итак, это не невозможно, но требует некоторой работы 🙂
Ответ №2:
У меня Tomcat 7.0.27.0
с JDK 1.6
Я использую tomcat только для аутентификации и not for authorization
Ниже приведена настройка
context.xml
<Realm className="org.apache.catalina.realm.JDBCRealm"
connectionName="login"
connectionPassword="password"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:authdb"
driverName="oracle.jdbc.OracleDriver"
userTable="appusers"
userNameCol="username"
userCredCol="password"
allRolesMode="authOnly"/>
web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/modules/*</url-pattern>
<url-pattern>/index.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<!--
security-role>
<role-name>user</role-name>
security-role>
-->
Я заставил его работать, удалив <security-role>
блок из web.xml amp;
ввод auth-contraint
с именем роли как *
Если вы удалите auth-contraint
блок из security-contraint
, то сама проверка подлинности веб-контекста не будет вызвана!!