雅加达EE 8安全> Wildfly 26 Elytron-未设定角色

发布于 2025-01-21 04:55:16 字数 8187 浏览 0 评论 0原文

我正在尝试使用Jakarta EE 8 Security设置一个简单的JSF登录,我已将登录页面作为自定义表单实现,如下所示:

@ApplicationScoped
@CustomFormAuthenticationMechanismDefinition(
    loginToContinue = @LoginToContinue(
        loginPage = "/user-login.xhtml",
        useForwardToLogin = false,
        errorPage = ""
    )
)
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class UserLoginConfig{
}

用户区域可确保以下servlet并定义单个角色“用户”:

@WebServlet("/user/*")
@DeclareRoles({"user"})
@ServletSecurity(@HttpConstraint(rolesAllowed = "user"))
public class UserLoginServlet extends HttpServlet {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

}

简单的JSF表单提交到登录bean

@Named
@ViewScoped
public class LoginBean implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private String password;
 
    private String email;
 
    @Inject private SecurityContext securityContext;
    @Inject private Logger log;
    
    public void login() throws IOException {

        ExternalContext externalContext = Faces.getExternalContext();
        AuthenticationStatus status = securityContext.authenticate(
            (HttpServletRequest) externalContext.getRequest(),
            (HttpServletResponse) externalContext.getResponse(),
            AuthenticationParameters.withParams()
              .credential(new UsernamePasswordCredential(email, password))
        );
        switch (status) {
            case SEND_CONTINUE:
                Faces.getContext().responseComplete();
                break;
            case SEND_FAILURE:
                Faces.getContext().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login failed", null));
                break;
            case SUCCESS:
                Faces.getContext().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO, "Login succeed", null));
                externalContext.redirect(externalContext.getRequestContextPath() + "/user/home.xhtml");
                break;
            case NOT_DONE:
        }
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    
    
}

和背景bean触发了在自定义itentityStore中实现的身份验证方法

@ApplicationScoped
public class MyIdentityStore implements IdentityStore {
    
    @Inject private UserDAOQueries userDAOQueries;
    @Inject private PasswordEncryptorEntities passwordEncryptor;

    @Override
    public int priority() {
        return 90;
    }

    @Override
    public Set<ValidationType> validationTypes() {
        return EnumSet.of(ValidationType.VALIDATE);
    }
    
    @Override
    public CredentialValidationResult validate(Credential credential) {
 
        UsernamePasswordCredential login = (UsernamePasswordCredential) credential;
 
        User user = userDAOQueries.findNonDeletedByEmail(login.getCaller());
        if (user!=null) {
            if(passwordEncryptor.isPasswordCorrect(login.getPasswordAsString(), user.getPassword())){
                Set<String> roles = new HashSet<String>();
                roles.add("user");
                
                return new CredentialValidationResult(login.getCaller(), roles);
            }else {
                return CredentialValidationResult.INVALID_RESULT;
            }
            
        } else {
            return CredentialValidationResult.NOT_VALIDATED_RESULT;
        }
    }

    @Override
    public Set<String> getCallerGroups(CredentialValidationResult validationResult) {
        Set<String> roles = new HashSet<String>();
        if(validationResult.getStatus().equals(Status.VALID)) {
            roles.add("user");
        }
        return roles;
    }
}

这一切都可以,并且用户被转发到/user/home.xhtml页面从服务器获得403禁止响应。 查看org.wildfly.security跟踪我可以看到“用户”角色在身份验证后未传递给容器(或者未正确映射)。

11:47:16,055 TRACE [org.wildfly.security] (default task-4) Handling CallerPrincipalCallback
11:47:16,055 TRACE [org.wildfly.security] (default task-4) Original Principal = 'javax.security.enterprise.CallerPrincipal@317242d5', Caller Name = 'null', Resulting Principal = 'javax.security.enterprise.CallerPrincipal@317242d5'
11:47:16,056 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,057 INFO  [io.undertow.accesslog] (default task-4) [14/Apr/2022:11:47:16 +0100] "POST /user-login.xhtml HTTP/1.1" 302 - - https HTTP/1.1
11:47:16,057 TRACE [org.wildfly.security.http.servlet] (default task-4) ServerAuthContext.validateRequest returned AuthStatus=AuthStatus.SEND_CONTINUE
11:47:16,065 TRACE [org.wildfly.security.http.servlet] (default task-4) Created ServletSecurityContextImpl enableJapi=true, integratedJaspi=false, applicationContext=my-webapp 
11:47:16,065 TRACE [org.wildfly.security] (default task-4) Handling CallerPrincipalCallback
11:47:16,065 TRACE [org.wildfly.security] (default task-4) Original Principal = 'javax.security.enterprise.CallerPrincipal@317242d5', Caller Name = 'null', Resulting Principal = 'javax.security.enterprise.CallerPrincipal@317242d5'
11:47:16,066 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,066 TRACE [org.wildfly.security.http.servlet] (default task-4) ServerAuthContext.validateRequest returned AuthStatus=AuthStatus.SUCCESS
11:47:16,066 TRACE [org.wildfly.security] (default task-4) No roles request of CallbackHandler.
11:47:16,066 TRACE [org.wildfly.security.http.servlet] (default task-4) Storing SecurityIdentity in HttpSession
11:47:16,066 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,068 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,068 TRACE [org.wildfly.security] (default task-4) Permission mapping: identity [javax.security.enterprise.CallerPrincipal@317242d5] with roles [] implies ("javax.security.jacc.WebResourcePermission" "/user/home.xhtml" "GET") = false
11:47:16,069 INFO  [io.undertow.accesslog] (default task-4) [14/Apr/2022:11:47:16 +0100] "GET /user/home.xhtml HTTP/1.1" 403 68 - https HTTP/1.1

我怀疑我在Elytron子系统中缺少一些配置代码>

在protionsow config I中,有一个应用程序 - 安全域定义为:

<application-security-domain name="other" security-domain="ApplicationDomain" enable-jaspi="true" integrated-jaspi="false"/>

在Elytron中,我的应用程序域配置为如下:

<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
                    <realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
                    <realm name="local"/>
                </security-domain>

使用默认的permission-mapper如下:

<simple-permission-mapper name="default-permission-mapper">
                    <permission-mapping>
                        <role name="user"/>
                        <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
                    </permission-mapping>
                </simple-permission-mapper>

我还尝试使用from from of proles-属性角色解码器,但这似乎根本无法正常工作

,我只是试图告诉Wildfly用户已登录并具有“ x”角色分配...

I am trying to setup a simple JSF login using Jakarta EE 8 Security, I have implemented the login page as a custom form as follows:

@ApplicationScoped
@CustomFormAuthenticationMechanismDefinition(
    loginToContinue = @LoginToContinue(
        loginPage = "/user-login.xhtml",
        useForwardToLogin = false,
        errorPage = ""
    )
)
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class UserLoginConfig{
}

The user area is secured with following servlet and defines a single role 'user':

@WebServlet("/user/*")
@DeclareRoles({"user"})
@ServletSecurity(@HttpConstraint(rolesAllowed = "user"))
public class UserLoginServlet extends HttpServlet {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

}

The simple JSF form submits to the LoginBacking bean

@Named
@ViewScoped
public class LoginBean implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private String password;
 
    private String email;
 
    @Inject private SecurityContext securityContext;
    @Inject private Logger log;
    
    public void login() throws IOException {

        ExternalContext externalContext = Faces.getExternalContext();
        AuthenticationStatus status = securityContext.authenticate(
            (HttpServletRequest) externalContext.getRequest(),
            (HttpServletResponse) externalContext.getResponse(),
            AuthenticationParameters.withParams()
              .credential(new UsernamePasswordCredential(email, password))
        );
        switch (status) {
            case SEND_CONTINUE:
                Faces.getContext().responseComplete();
                break;
            case SEND_FAILURE:
                Faces.getContext().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login failed", null));
                break;
            case SUCCESS:
                Faces.getContext().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO, "Login succeed", null));
                externalContext.redirect(externalContext.getRequestContextPath() + "/user/home.xhtml");
                break;
            case NOT_DONE:
        }
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
    
    
}

And the backing bean triggers the authenticate method that is implemented within a custom ItentityStore

@ApplicationScoped
public class MyIdentityStore implements IdentityStore {
    
    @Inject private UserDAOQueries userDAOQueries;
    @Inject private PasswordEncryptorEntities passwordEncryptor;

    @Override
    public int priority() {
        return 90;
    }

    @Override
    public Set<ValidationType> validationTypes() {
        return EnumSet.of(ValidationType.VALIDATE);
    }
    
    @Override
    public CredentialValidationResult validate(Credential credential) {
 
        UsernamePasswordCredential login = (UsernamePasswordCredential) credential;
 
        User user = userDAOQueries.findNonDeletedByEmail(login.getCaller());
        if (user!=null) {
            if(passwordEncryptor.isPasswordCorrect(login.getPasswordAsString(), user.getPassword())){
                Set<String> roles = new HashSet<String>();
                roles.add("user");
                
                return new CredentialValidationResult(login.getCaller(), roles);
            }else {
                return CredentialValidationResult.INVALID_RESULT;
            }
            
        } else {
            return CredentialValidationResult.NOT_VALIDATED_RESULT;
        }
    }

    @Override
    public Set<String> getCallerGroups(CredentialValidationResult validationResult) {
        Set<String> roles = new HashSet<String>();
        if(validationResult.getStatus().equals(Status.VALID)) {
            roles.add("user");
        }
        return roles;
    }
}

This all works ok and the user is forwarded to the /user/home.xhtml page successfully, however I am then getting a 403 Forbidden response from the server.
Looking at the org.wildfly.security TRACE I can see that the 'user' role is not being passed to the container following authentication (or they aren't being mapped correctly).

11:47:16,055 TRACE [org.wildfly.security] (default task-4) Handling CallerPrincipalCallback
11:47:16,055 TRACE [org.wildfly.security] (default task-4) Original Principal = 'javax.security.enterprise.CallerPrincipal@317242d5', Caller Name = 'null', Resulting Principal = 'javax.security.enterprise.CallerPrincipal@317242d5'
11:47:16,056 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,057 INFO  [io.undertow.accesslog] (default task-4) [14/Apr/2022:11:47:16 +0100] "POST /user-login.xhtml HTTP/1.1" 302 - - https HTTP/1.1
11:47:16,057 TRACE [org.wildfly.security.http.servlet] (default task-4) ServerAuthContext.validateRequest returned AuthStatus=AuthStatus.SEND_CONTINUE
11:47:16,065 TRACE [org.wildfly.security.http.servlet] (default task-4) Created ServletSecurityContextImpl enableJapi=true, integratedJaspi=false, applicationContext=my-webapp 
11:47:16,065 TRACE [org.wildfly.security] (default task-4) Handling CallerPrincipalCallback
11:47:16,065 TRACE [org.wildfly.security] (default task-4) Original Principal = 'javax.security.enterprise.CallerPrincipal@317242d5', Caller Name = 'null', Resulting Principal = 'javax.security.enterprise.CallerPrincipal@317242d5'
11:47:16,066 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,066 TRACE [org.wildfly.security.http.servlet] (default task-4) ServerAuthContext.validateRequest returned AuthStatus=AuthStatus.SUCCESS
11:47:16,066 TRACE [org.wildfly.security] (default task-4) No roles request of CallbackHandler.
11:47:16,066 TRACE [org.wildfly.security.http.servlet] (default task-4) Storing SecurityIdentity in HttpSession
11:47:16,066 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,068 TRACE [org.wildfly.security] (default task-4) Role mapping: principal [javax.security.enterprise.CallerPrincipal@317242d5] -> decoded roles [] -> domain decoded roles [] -> realm mapped roles [] -> domain mapped roles []
11:47:16,068 TRACE [org.wildfly.security] (default task-4) Permission mapping: identity [javax.security.enterprise.CallerPrincipal@317242d5] with roles [] implies ("javax.security.jacc.WebResourcePermission" "/user/home.xhtml" "GET") = false
11:47:16,069 INFO  [io.undertow.accesslog] (default task-4) [14/Apr/2022:11:47:16 +0100] "GET /user/home.xhtml HTTP/1.1" 403 68 - https HTTP/1.1

I suspect I am missing some config in the elytron subsystem, I have a custom security domain <security-domain>other</security-domain> defined in jboss-web.xml

In undertow config I have an application-security-domain defined as such:

<application-security-domain name="other" security-domain="ApplicationDomain" enable-jaspi="true" integrated-jaspi="false"/>

In Elytron I have the ApplicationDomain configured as follows:

<security-domain name="ApplicationDomain" default-realm="ApplicationRealm" permission-mapper="default-permission-mapper">
                    <realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
                    <realm name="local"/>
                </security-domain>

With the default-permission-mapper as follows:

<simple-permission-mapper name="default-permission-mapper">
                    <permission-mapping>
                        <role name="user"/>
                        <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
                    </permission-mapping>
                </simple-permission-mapper>

I have also tried using the from-roles-attribute role decoder but that doesn't seem to work

Essentially I am just trying to tell Wildfly that the user has logged in and has 'x' roles assigned...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一瞬间的火花 2025-01-28 04:55:17

好的,如果有人正在寻找答案,如果您使用的是@customformauthenticationmechanismdefinition使用自定义IdentityStore,则需要实现两个覆盖验证方法的IdentityStore(如我上面显示的一个)另一个通过覆盖getCallerGroups方法和设置validatytype.provide_groups

。 2个身份存储不需要,只是不要覆盖验证类型,它可以同时完成

Ok in case anyone is looking for the answer to this, if you are using @CustomFormAuthenticationMechanismDefinition with a Custom IdentityStore you need to implement two IdentityStore's one that overrides the validate method (like the one I have shown above) and another that assigns the roles/groups by overriding the getCallerGroups method and setting ValidationType.PROVIDE_GROUPS....then the roles are assigned to the principal and all is good

UPDATE: 2 identity stores not required, just don't override the ValidationType at all and it can do both

吐个泡泡 2025-01-28 04:55:17

也许您缺少EJB3子系统的配置来将安全域名映射到Elytron安全域?

/subsystem=ejb3/application-security-domain=other:add(security-domain=ApplicationDomain)

Maybe you are missing configuration of the EJB3 subsystem to map a security domain name to an Elytron security domain?

/subsystem=ejb3/application-security-domain=other:add(security-domain=ApplicationDomain)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文