Java 웹 응용 프로그램 : 사용자 정의 영역 사용
-
23-08-2019 - |
문제
웹 서비스를 통해 로그인을 수행 해야하는 Java 웹 응용 프로그램을 작성하고 있습니다. 물론, 내가 사용하고있는 애플리케이션 서버 (Glassfish V2)와 함께 제공되는 영역 중 어느 것도 트릭을 수행 할 수 없습니다. 그러므로 나는 내 자신을 써야했다. 그러나 내가 쓴 영역 구현은 Glassfish와 완전히 연결되어 있으며 다른 응용 프로그램 서버에서와 같이 사용할 수 없습니다.
사용자 정의 영역을 구현할 수있는 표준 또는 널리 지원되는 방법이 있습니까? .war에서 해당 영역을 배포 할 수 있습니까? 아니면 서버의 자체 클래스 경로에서 항상로드해야합니까?
해결책
참고 : 아래의 답변은 Java EE 5에만 유효합니다. 다른 답변 중 하나에서 주목을받는 것처럼 Java EE 6이이를 뒷받침합니다. 따라서 Java EE 6을 사용하는 경우이 답을 읽지 말고 다른 관련 답변을 읽으십시오.
내 자신의 연구 와이 질문에 대한 답변에서 내가 찾은 답변은 다음과 같습니다. JAA는 표준 인터페이스이지만 다양한 응용 프로그램 서버에 JAAS Realm + LoginModule을 작성, 배포 및 통합하는 균일 한 방법은 없습니다.
Glassfish V2를 사용하면 LoginModule 또는 Realm 자체를 구현하는 자체 내부 클래스를 확장해야합니다. 그러나 LoginModule 인터페이스의 많은 방법이 Glassfish의 슈퍼 클래스에서 최종적으로 표시되므로 전체 로그인 프로세스를 사용자 정의 할 수 없습니다. 사용자 정의 LoginModule 및 Realm 클래스는 AS ClassPath (응용 프로그램이 아닌)에 배치해야하며 영역은 수동으로 등록되어야합니다 (.WAR에서 배포되지 않음).
Tomcat의 상황은 약간 더 나은 것 같습니다. 이는 자신의 영역과 LoginModule을 완전히 코딩 한 다음 자체 JaasRealm을 사용하여 응용 프로그램 서버로 구성 할 수 있습니다 (실제 작업을 Realm 및 LoginModule의 구현에 위임 할 것입니다). . 그러나 Tomcat조차도 .war에서 사용자 정의 영역을 배포 할 수 없습니다.
내 결과를 나타낸 응용 프로그램 서버 중 어느 것도 모든 JAAS 콜백을 최대한 활용할 수없는 것 같습니다. 그들 모두는 기본 사용자 이름+비밀번호 체계 만 지원하는 것 같습니다. 그보다 더 복잡한 것이 필요한 경우 Java EE 컨테이너가 관리하지 않는 솔루션을 찾아야합니다.
참조를 위해, 그리고 내 질문에 대한 의견에 묻기 때문에 Glassfishv2에 대해 쓴 코드는 다음과 같습니다.
우선, 여기에 영역 구현이 있습니다.
public class WebserviceRealm extends AppservRealm {
private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());
private String jaasCtxName;
private String hostName;
private int port;
private String uri;
@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
_logger.info("My Webservice Realm : init()");
// read the configuration properties from the user-supplied properties,
// use reasonable default values if not present
this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
this.hostName = props.getProperty("hostName", "localhost");
this.uri = props.getProperty("uri", "/myws/EPS");
this.port = 8181;
String configPort = props.getProperty("port");
if(configPort != null){
try{
this.port = Integer.parseInt(configPort);
}catch(NumberFormatException nfe){
log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
}
}
}
@Override
public String getJAASContext() {
return jaasCtxName;
}
public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
List groupNames = new LinkedList();
return (Enumeration) groupNames;
}
public String getAuthType() {
return "My Webservice Realm";
}
public String getHostName() {
return hostName;
}
public int getPort() {
return port;
}
public String getUri() {
return uri;
}
}
그런 다음 LoginModule 구현 :
public class WebserviceLoginModule extends AppservPasswordLoginModule {
// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately
@Override
protected void authenticateUser() throws LoginException {
if (_username == null || _password == null) {
throw new LoginException("username and password cannot be null");
}
String[] groups = this.getWebserviceClient().login(_username, _password);
// must be called as last operation of the login method
this.commitUserAuthentication(groups);
}
@Override
public boolean commit() throws LoginException {
if (!_succeeded) {
return false;
}
// fetch some more information through the webservice...
return super.commit();
}
private WebserviceClient getWebserviceClient(){
return theWebserviceClient;
}
}
마지막으로, 영역에서 로그 모듈에 연결되어야합니다. 이것은 Glassfish V2에서 Domain/Config/Login.conf에있는 JAAS 구성 파일 레벨에서 수행됩니다. 해당 파일 끝에 다음 줄을 추가하십시오.
myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
my.auth.login.WebserviceLoginModule required;
};
이것이 유리 피쉬에서 나를 위해 일하는 것들입니다. 다시 말하지만,이 솔루션은 애플리케이션 서버에서 휴대용이 없지만, 내가 알 수있는 한, 기존 휴대용 솔루션은 없습니다.
다른 팁
사용자 정의 영역을 구현할 수있는 표준 또는 널리 지원되는 방법이 있습니까? .war에서 해당 영역을 배포 할 수 있습니까? 아니면 서버의 자체 클래스 경로에서 항상로드해야합니까?
사용자 정의 영역을 구현하거나 일반적인 용어로 사용자 정의 인증 모듈을 구현하는 표준 방법이 절대적으로 있습니다. 이것은 그것을 통해 할 수 있습니다 jaspic/jaspi/jsr 196 SPI/API. Jaspic은 전체 Java EE 6 구현의 표준 부분이지만 불행히도 Java EE 6 웹 프로파일의 일부는 아닙니다.
그러나 Jaspic이 Java EE 6의 일부 임에도 불구하고 공급 업체는 최적의 지원을받지 않습니다. Glassfish와 Weblogic은 매우 좋은 구현을 가지고있는 것 같습니다. Jboss AS와 Geronimo는 조금 더 문제가됩니다. 이 주제 (Anil Saldhana)에 관한 JBoss의 주요 엔지니어는 심지어 기본적으로 jaspic 활성화를 거부합니다 순간. 7.1로 JBoss에서 가장 심각한 버그 중 일부는 최근에 고정되었습니다, 그러나 더 이상 예약 된 JBoss 7.1.x의 공개 릴리스가없고 7.2로 JBoss는 여전히 시간이 지남에 따라 JBoss Jaspic에서는 지금까지는 번거로운 의미입니다.
또 다른 불행한 문제는 실제 인증 모듈이 표준화 될 수 있지만 표준화 된 구성 방법 (XML 파일 읽기)은 없다는 것입니다.
.war에서 해당 영역을 배포 할 수 있습니까? 아니면 서버의 자체 클래스 경로에서 항상로드해야합니까?
Jaspic을 사용하면 인증 모듈 ( 'realm')을 실제로 .war에서로드 할 수 있습니다. 나는 이것이 사양에 의해 보장되는지 여부를 100% 확신하지 못하지만, 내가 테스트 한 4 개의 서버 중 (Glassfish, Weblogic, Geronimo 및 Jboss As), 그들은 모두 이것을 지원했습니다. Geronimo는 불행히도 프로그래밍 방식 등록에 어떤 종류의 레이스 조건이 있으므로 핫 배치를 두 번 수행하여 추악한 해결 방법이 필요하지만 결국 .war에서 모듈을로드하면 결국에는 IT가 있습니다.
독점 메커니즘에 따라, 적어도 jboss는 항상 .war 또는 .ear에서 모듈로드 (예 : org.jboss.security.auth.auth.abstractserverloginmodule의 서브 클래스)를 지원했습니다.
나 블로그 게시물을 썼습니다 이 주제에 대해 최근에 더 자세한 내용이 있습니다.
영역은 응용 프로그램 인공물이 아니기 때문에 전쟁에서 영역을 배치 할 수 없습니다. 컨테이너 아티팩트 (따라서 "컨테이너 기반 보안"이라는 문구). 컨테이너에서 제공 한 특정 영역을 사용하도록 앱을 구성 할 수 있지만 응용 프로그램은이 자체를 제공 할 수 없습니다.
즉, 모든 컨테이너가 다르지만 이러한 영역은 휴대용이 아니지만 간단한 상식은 휴대 성을 찾고 있다면 컨테이너와 통합하는 데 필요한 작은 접착제 코드의 차이를 줄입니다.
SUNS 문서를 빠르게 살펴보면 앱 서버 특정 클래스를 확장하는 사용자 정의 로그 인 모드를 작성 해야하는 것처럼 보입니다. 이것은 나에게 약간 거꾸로 보이고 유리 피쉬의 한계가 있습니다.
이것을보다 휴대용으로 만들고 싶다면 표준 Javaee 인터페이스에 대해 개발 된 사용자 정의 로그 인 모드에 대부분의 구현을 넣은 다음 표준의 휴대용 구현에 위임하는 Glassfish에 특정한 얇은 구현 계층을 갖는 것이 좋습니다. .
체크 아웃 이 주제에 관한 Sun의 기사.
나는 실제로 이것을 직접 한 적이 없지만, 나는 당신에게 새로운 영역 (보안 도메인)을 등록 할 수있는 옵션을 제공한다고 확신합니다.
아마도 100% 휴대용이 아니며 각각 다른 구성 XML이 필요할 수 있지만 기본적으로 코드가 다른 이유는 없습니다.