Я хочу понять безопасность на основе форм и области JDBC с помощью glassfishV3, поэтому я решил создать небольшое приложение, которое просто позволяет входить и выходить, я следовал инструкциям из этого book, чтобы сделать это.
Я понимаю, как работает трюк, но что-то не так, и я не могу заставить его работать правильно.
Сначала я создал небольшую базу данных с аннотациями JPA:
@Entity
@Table(name="USERS")
public class User implements Serializable {
private static final long serialVersionUID = -1244856316278032177L;
@Id
@GeneratedValue
@Column(nullable = false)
private Long id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
@OneToMany(mappedBy = "user")
private List<Group> groups;
//GET & SET METHODS...
}
Здесь другая таблица, которая содержит роли для каждого пользователя
@Entity
@Table(name="GROUPS")
public class Group implements Serializable {
private static final long serialVersionUID = -7274308564659753174L;
@Id
@GeneratedValue
@Column(nullable = false)
private Long id;
@Column(nullable = false)
private String groupName;
@ManyToOne
@JoinColumn(name = "USERS_ID", nullable = false)
private User user;
//GET & SET METHODS...
}
Когда БД была готова, я добавил некоторые данные вручную
Следующим шагом было настроить область безопасности.
Затем добавлена настройка безопасности в файл web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>CHAPTER x 12 Container Managed Authentication and
Authorization</display-name>
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>VISITOR PERMISIONS</web-resource-name>
<url-pattern>/index.xhtml</url-pattern>
<url-pattern>/visitorpanel.xhtml</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>visitors</role-name>
<role-name>users</role-name>
<role-name>administrators</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>USERS PERMISIONS</web-resource-name>
<url-pattern>/userpanel.xhtml</url-pattern>
<url-pattern>/index.xhtml</url-pattern>
<url-pattern>/visitorpanel.xhtml</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>users</role-name>
<role-name>administrators</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>ADMIN PERMISIONS</web-resource-name>
<url-pattern>/adminpanel.xhtml</url-pattern>
<url-pattern>/userpanel.xhtml</url-pattern>
<url-pattern>/index.xhtml</url-pattern>
<url-pattern>/visitorpanel.xhtml</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>administrators</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>DBRealm</realm-name>
<form-login-config>
<form-login-page>/index.xhtml</form-login-page>
<form-error-page>/error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>visitors</role-name>
</security-role>
<security-role>
<role-name>users</role-name>
</security-role>
<security-role>
<role-name>administrators</role-name>
</security-role>
</web-app>
Мои цели здесь были:
-
администраторы могут видеть все страницы
-
посетители могут видеть только index.xhtml и visitorpanel.xhtml
-
пользователи могут видеть index.xhtml, visitorpanel.xhtml и userpanel.xhtml
Я думаю, что правильная конфигурация.
Наконец, последним шагом было создание формы входа на странице index.xhtml:
<form method="post" action="j_security_check" name="loginForm">
<h:outputLabel id="userNameLabel" for="j_username" value="Enter your [email protected]:"/>
<h:inputText id="j_username" autocomplete="off" />
<br/>
<h:outputLabel id="passwordLabel" for="j_password" value="Enter your [email protected] password:"/>
<h:inputSecret id="j_password" autocomplete="off"/>
<br/>
<h:commandButton type="submit" value="Login"/>
<h:commandButton type="reset" value="Clear"/>
</form>
Программа строит отлично, но у меня есть следующие проблемы:
1- Когда я пытаюсь войти в систему как пользователь или администратор (посетителям не нужно входить в систему), я перенаправляюсь на страницу error.xhtml, а в консоли вижу исключение:
SEVERE: SEC1112: не удается проверить пользователя [[email protected]] для JDBC область. ПРЕДУПРЕЖДЕНИЕ: Ошибка входа в Интернет: Ошибка входа: javax.security.auth.login.LoginException: исключение безопасности ПРЕДУПРЕЖДЕНИЕ: PWC4011: невозможно установить кодировку символов запроса в UTF-8 из контекст /CHAPTER _12_x_Container_Managed_Authentication_and_Authorization, потому что параметры запроса уже прочитаны или ServletRequest.getReader() уже был вызван
2- Когда я пытаюсь перейти к некоторым страницам через URL-адрес, ничего не происходит. Я думаю, что все в порядке, но когда я пытаюсь посетить guestpanel.xhtml, это должно позволить мне, потому что нет необходимости регистрироваться, чтобы увидеть его. Нужно ли мне удалять эту страницу из конфигурации безопасности, если вы хотите, чтобы все ее тела видели?
3 Также мне интересно, почему я не могу использовать тег h: form вместо простой формы, когда я реализую логин?
Я действительно ценю некоторую помощь, я был несколько часов, читая первые главы книги и пытаясь реализовать, мой собственный пример, но я застрял. Я думаю, что я близок к решению.
Обновление
Я изменил принцип Default, чтобы быть именем пользователя посетителей. Но он все еще не работает.
И я также добавил некоторые дополнительные параметры в конфигурацию Realm
Но когда я пытаюсь войти в систему, я все еще вижу исключение, которое говорит:
SEVERE: SEC1112: не удается проверить пользователя [[email protected]] для JDBC область. ПРЕДУПРЕЖДЕНИЕ: Ошибка входа в Интернет: Ошибка входа: javax.security.auth.login.LoginException: исключение безопасности ПРЕДУПРЕЖДЕНИЕ: PWC4011: невозможно установить кодировку символов запроса в UTF-8 из контекст /CHAPTER _12_x_Container_Managed_Authentication_and_Authorization, потому что параметры запроса уже прочитаны или ServletRequest.getReader() уже был вызван
Я до сих пор не знаю, чего не хватает.
-Возможно, что имя таблицы не должно быть в верхнем регистре?
-Возможно, что имена столбцов не должны быть в верхнем регистре?
- Может быть, таблицы созданы неправильно?
- Может быть, я не могу использовать PASSWORD в качестве имени столбца, потому что он создает какой-то конфликт?
Я действительно не понимаю, почему это исключение. Я пинговал базу данных с панели администратора, и все выглядят правильно.
Может кто-нибудь помочь мне разобраться с этим?
Обновление 2
Я изменил параметр ведения журнала "javax.enterprise.system.core.security" на уровень FINE, чтобы иметь больше информации, когда происходят исключения, это был результат, когда я попытался войти в систему:
FINE: Перехват ввода: перехват: SOAP defaultServerID: null defaultClientID: null FINE: ID Entry: Класс модуля: com.sun.xml.wss.provider.ClientSecurityAuthModule id: XWS_ClientProvider тип: клиент политика запроса: [email protected] политика ответа: [email protected] options: {signature.key.alias = s1as, debug = false, dynamic.username.password = false, encryption.key.alias = s1as} FINE: ID Вступление: Класс модуля: com.sun.xml.wss.provider.ClientSecurityAuthModule id: ClientProvider тип: клиент политика запроса: [email protected] политика реагирования: [email protected] options: {signature.key.alias = s1as, debug = false, dynamic.username.password = false, encryption.key.alias = s1as, security.config = C:\jeeAplicationServer\glassfishv3\GlassFish\доменов\домен1/конфигурация/WSS-сервер конфигурация-1.0.xml} FINE: ID Entry: Класс модуля: com.sun.xml.wss.provider.ServerSecurityAuthModule id: XWS_ServerProvider Тип: сервер политика запроса: [email protected] политика ответа: [email protected] options: {signature.key.alias = s1as, debug = false, encryption.key.alias = s1as} FINE: ID Entry: Класс модуля: com.sun.xml.wss.provider.ServerSecurityAuthModule id: ServerProvider Тип: сервер политика запроса: [email protected] политика ответа: [email protected] options: {signature.key.alias = s1as, debug = false, encryption.key.alias = s1as, security.config = C:\jeeAplicationServer\glassfishv3\GlassFish\доменов\домен1/конфигурация/WSS-сервер конфигурация-1.0.xml} FINE: [Web-Security] Политика настройки Идентификатор контекста: old = null ctxID = CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission/j_security_check POST) FINE: [Web-Security] hasUserDataPermission isGranted: true FINE: Вход в систему [admi[email protected]] в область: DBRealm с использованием JAAS module: jdbcRealm FINE: модуль входа в систему инициализирован: класс com.sun.enterprise.security.auth.login.JDBCLoginModule SEVERE: SEC1112: Невозможно проверить пользователя [[email protected]] для области JDBC. FINE: Не удалось проверить пользователя javax.security.auth.login.LoginException: невозможно для подключения к datasource jdbc/security для пользователя базы данных. в com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.getConnection(JDBCRealm.java:550) в com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.isUserValid(JDBCRealm.java:393) в com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.authenticate(JDBCRealm.java:311) в com.sun.enterprise.security.auth.login.JDBCLoginModule.authenticate(JDBCLoginModule.java:72) в com.sun.enterprise.security.auth.login.PasswordLoginModule.authenticateUser(PasswordLoginModule.java:90) в com.sun.appserv.security.AppservPasswordLoginModule.login(AppservPasswordLoginModule.java:141) at sun.reflect.NativeMethodAccessorImpl.invoke0 (Нативный метод) в sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) в sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) в java.lang.reflect.Method.invoke(Method.java:597) в javax.security.auth.login.LoginContext.invoke(LoginContext.java:769) в javax.security.auth.login.LoginContext.access $000 (LoginContext.java:186) в javax.security.auth.login.LoginContext $4.run(LoginContext.java:683) в java.security.AccessController.doPrivileged(собственный метод) в javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) в javax.security.auth.login.LoginContext.login(LoginContext.java:579) в com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:341) в com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:199) в com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:152) в com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:479) в com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:418) в org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:264) в org.apache.catalina.authenticator.AuthenticatorBase.processSecurityCheck(AuthenticatorBase.java:1015) в org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:614) в org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:615) на com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) в com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85) в org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185) в org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325) в org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226) в com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165) в com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791) в com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693) на com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954) в com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170) в com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135) в com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) в com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) в com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) в com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53) в com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57) на com.sun.grizzly.ContextTask.run(ContextTask.java:69) в com.sun.grizzly.util.AbstractThreadPool $Worker.doWork(AbstractThreadPool.java:330) в com.sun.grizzly.util.AbstractThreadPool $Worker.run(AbstractThreadPool.java:309) на java.lang.Thread.run(Thread.java:662) Вызвано: javax.naming.NamingException: не удалось выполнить поиск для 'jdbc/security' в SerialContext [Исключение корня - javax.naming.NameNotFoundException: безопасность не найдена] com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:442) в javax.naming.InitialContext.lookup(InitialContext.java:392) в javax.naming.InitialContext.lookup(InitialContext.java:392) в com.sun.enterprise.connectors.service.ConnectorResourceAdminServiceImpl.lookup(ConnectorResourceAdminServiceImpl.java:203) в com.sun.enterprise.connectors.ConnectorRuntime.lookupNonTxResource(ConnectorRuntime.java:440) в com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.getConnection(JDBCRealm.java:538) ... 44 more Причиненный: javax.naming.NameNotFoundException: безопасность не найден com.sun.enterprise.naming.impl.TransientContext.doLookup(TransientContext.java:197) в com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:168) в com.sun.enterprise.naming.impl.TransientContext.lookup(TransientContext.java:172) в com.sun.enterprise.naming.impl.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:58) в com.sun.enterprise.naming.impl.LocalSerialContextProviderImpl.lookup(LocalSerialContextProviderImpl.java:101) в com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:430) ... 49 больше
FINE: аутентификация JAAS отменена. ПРЕДУПРЕЖДЕНИЕ: Ошибка входа в Интернет: Логин failed: javax.security.auth.login.LoginException: исключение безопасности FINE: идентификатор контекста политики [Web-Security]: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission/error.xhtml GET) FINE: [Web-Security] hasUserDataPermission isGranted: true
Обновление 3
Может быть, есть что-то wron с пулом соединений. Вот как выглядит мой пул соединений:
У меня нет свойств, возможно, что-то не хватает?
Также теперь я создал ресурс JDBC, который выглядит следующим образом:
(Имя JNDI в Realm, было изменено на jdbc/studydb)
Мой persistence.xml выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="CHAPTER x 12 Container Managed Authentication and Authorization">
<jta-data-source>jdbc/studydb</jta-data-source>
<class>entities.User</class>
<class>entities.Group</class>
</persistence-unit>
</persistence>
Я думаю, что сделал некоторый прогресс, теперь я вижу следующее исключение:
> SEVERE: jdbcrealm.invaliduserreason
> FINE: Cannot validate user
> java.sql.SQLSyntaxErrorException: Schema 'ADMIN' does not exist
> at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown
> Source)
> ....
>
> Caused by: org.apache.derby.client.am.SqlException: Schema 'ADMIN' does not exist
> at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
> ...
> FINE: JAAS authentication aborted.
> WARNING: Web login failed: Login failed: javax.security.auth.login.LoginException: Security Exception
> FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
> FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /error.xhtml GET)
> FINE: [Web-Security] hasUserDataPermission isGranted: true
> WARNING: PWC4011: Unable to set request character encoding to UTF-8 from context
> /CHAPTER_12_x_Container_Managed_Authentication_and_Authorization,
> because request parameters have already been read, or
> ServletRequest.getReader() has already been called
Обновление 4
Я изменил базу данных, это было неправильно организовано, поэтому я внес некоторые изменения в мои сущности:
@Entity
@Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
private static final long serialVersionUID = -1244856316278032177L;
@Id
@Column(nullable = false)
private String userid;
@Column(nullable = false)
private String password;
@ManyToOne
@JoinTable(name="USER_GROUP",schema="ADMIN", joinColumns = @JoinColumn(name="userid", referencedColumnName="userid"), [email protected](name="groupid", referencedColumnName= "groupid") )
private Group group;
//GET & SET METHODS
@Entity @Table (name= "GROUPS", schema = "ADMIN" ) группа public class реализует Serializable {
private static final long serialVersionUID = -7274308564659753174L;
@Id
@Column(nullable = false)
private String groupid;
@OneToMany(mappedBy="group")
private Set<User> users;
//GET и SET METHODS
Поэтому мне также пришлось отредактировать DBRealm, теперь он выглядит так:
Но когда я вхожу в систему, я снова получаю исключение:
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /j_security_check POST)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: Logging in user [[email protected]] into realm: DBRealm using JAAS module: jdbcRealm
FINE: Login module initialized: class com.sun.enterprise.security.auth.login.JDBCLoginModule
SEVERE: SEC1111: Cannot load group for JDBC realm user [[email protected]].
FINE: Cannot load group
java.sql.SQLSyntaxErrorException: Column 'USERID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE statement then 'USERID' is not a column in the target table.
....
....
Caused by: org.apache.derby.client.am.SqlException: Column 'USERID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE statement then 'USERID' is not a column in the target table.
at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
....
....
FINE: JAAS login complete.
FINE: JAAS authentication committed.
FINE: Password login succeeded for : [email protected]
FINE: permission check done to set SecurityContext
FINE: Set security context as user: [email protected]
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission GET)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: permission check done to set SecurityContext
FINE: SecurityContext: setCurrentSecurityContext method called
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] hasUserDataPermission perm: (javax.security.jacc.WebUserDataPermission /adminpanel.xhtml GET)
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] Generating a protection domain for Permission check.
FINE: [Web-Security] Checking with Principal : [email protected]
FINE: [Web-Security] Checking with Principal : visitors
FINE: [Web-Security] Checking with Principal : users
FINE: [Web-Security] Checking with Principal : administrators
FINE: [Web-Security] Codesource with Web URL: file:/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization/CHAPTER_x_12_Container_Managed_Authentication_and_Authorization
FINE: [Web-Security] Checking Web Permission with Principals : [email protected], visitors, users, administrators
FINE: [Web-Security] Web Permission = (javax.security.jacc.WebResourcePermission /adminpanel.xhtml GET)
FINE: [Web-Security] hasResource isGranted: true
FINE: [Web-Security] hasResource perm: (javax.security.jacc.WebResourcePermission /adminpanel.xhtml GET)
FINE: SecurityContext: setCurrentSecurityContext method called
WARNING: Resource not found: com/sun/enterprise/v3/admin/adapter/theme/com/sun/webui/jsf/suntheme/images/masthead/masthead_button_over.gif