문제

웹 서비스를 통해 로그인을 수행 해야하는 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이 필요할 수 있지만 기본적으로 코드가 다른 이유는 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top