OpenLiberty / open-liberty

Open Liberty is a highly composable, fast to start, dynamic application server runtime environment
https://openliberty.io
Eclipse Public License 2.0
1.16k stars 599 forks source link

appSecurity Jakarta Security overrides mpJwt #12253

Open ggam opened 4 years ago

ggam commented 4 years ago

Describe the bug

I'm trying to use Jakarta EE Security for authenticating users via basic auth and via JWT afterwards. The problem is that Jakarta EE Security seems to always take precedence over MP JWT, efectively disabling it. Liberty always takes Jakarta EE Security for authentication.

Steps to Reproduce server.xml with MP JWT filtered for "Authorization Bearer" requests (removing the filter doesn't fix the problem anyway)

<?xml version="1.0" encoding="UTF-8"?>
<server description="${project.name}">
    <featureManager>
        <feature>appSecurity-3.0</feature>
        <!--<feature>javaee-8.0</feature>-->
        <feature>microProfile-3.3</feature>
        <feature>jpaContainer-2.2</feature>
        <feature>bells-1.0</feature>
    </featureManager>

    <httpEndpoint id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443" />

    <ssl id="defaultSSLConfig" trustDefaultCerts="true" />
    <defaultKeyStore password="changeit" />

    <webApplication location="${project.name}.war" contextRoot="/">
        <classloader commonLibraryRef="hibernate"/>
    </webApplication>

    <mpJwt
        id="myMpJwt"
        jwksUri="https://example.com/api/jwk"
        issuer="simpleIssuer"
        audiences="simpleApp">
        <authFilter>
            <requestHeader id="basicAuth" name="Authorization" value="Bearer" matchType="contains" />
        </authFilter>
    </mpJwt>

    <logging traceSpecification="*=audit" />

    <dataSource id="DefaultDataSource" jndiName="jdbc/myApp">
        <jdbcDriver 
            javax.sql.XADataSource="org.h2.jdbcx.JdbcDataSource"
            javax.sql.ConnectionPoolDataSource="org.h2.jdbcx.JdbcDataSource"
            javax.sql.DataSource="org.h2.jdbcx.JdbcDataSource">
            <library>
                <fileset dir="${server.config.dir}/lib/h2"/>
            </library>
        </jdbcDriver>
        <properties URL="jdbc:h2:file:${server.config.dir}/resources/myapp_db"/>
    </dataSource>

    <library id="hibernate">
        <fileset dir="${server.config.dir}/lib/hibernate"/>
    </library>

    <bell libraryRef="hibernate" />
</server>

AuthConfig.java

@BasicAuthenticationMechanismDefinition(realmName = "defaultRealm")
@DatabaseIdentityStoreDefinition(
        dataSourceLookup = "jdbc/myApp",
        callerQuery = "select password from users where username = ?",
        groupsQuery = "select role_name from groups username = ?"
)
@Dependent
public class AuthConfig {

}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <security-constraint>
        <web-resource-collection>
            <url-pattern>/resources/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
</web-app>

With this configuration, I do a Postman request to http://localhost:9080/resources with header "Authorization Bearer XXXX" and I get the following messages.log entry:

[INFO    ] CWWKS1652A: Authentication failed with status AuthStatus.SEND_FAILUR for the web request /resources. The user defined Java Authentication SPI for Containers (JASPIC) service null has determined that the authentication data is not valid.

I then remove @BasicAuthenticationMechanismDefinition(realmName = "defaultRealm") to disable Jakarta Security. The same requests (invalid token) gives the following result:

[INFO    ] CWWKS4358I: The authentication filter mpJwt[myMpJwt]//com.ibm.ws.security.authentication.filter(authFilter)[default-0] configuration was successfully processed.
[ERROR   ] CWWKS6049E: A JSON Web Key (JWK) was not returned from the URL [https://example.com/api/jwk]. The response status was [0] and the content returned was [IOException: No such host is known (example.com) null].
[ERROR   ] CWWKS5524E: The MicroProfile JWT feature encountered an error while creating a JWT by using the [myMpJwt] configuration and the token included in the request. CWWKS6031E: The JSON Web Token (JWT) consumer [myMpJwt] cannot process the token string. CWWKS6029E: The JSON Web Token (JWT) cannot be validated because a signing key cannot be found. The configured signature algorithm [RS256] requires a key to validate the token. 
[ERROR   ] CWWKS5523E: The MicroProfile JWT feature cannot authenticate the request because the token that is included in the request cannot be validated. CWWKS5524E: The MicroProfile JWT feature encountered an error while creating a JWT by using the [myMpJwt] configuration and the token included in the request. CWWKS6031E: The JSON Web Token (JWT) consumer [myMpJwt] cannot process the token string. CWWKS6029E: The JSON Web Token (JWT) cannot be validated because a signing key cannot be found. The configured signature algorithm [RS256] requires a key to validate the token. 

Expected behavior Jakarta Security should authenticate the user when there's no "Authorization Bearer" header present. MP JWT should be used when there is.

Diagnostic information:

utle commented 4 years ago

Hi, This is worked as designed. If you have a need to allow fallback from MP JWT to JSR-375 BasicAuth, you need to open an RFE https://www.ibm.com/developerworks/rfe/execute?use_case=submitRfe so other customers can vote it.

Thanks, Ut Le

ggam commented 4 years ago

Hi @utle. I'll create a RFE (thanks for the link) but let me clarify my use case. I'm really trying to use JSR 375 for the IdentityStore, as I don't want to implement a Liberty UserRegistry, which is non portable.

Fallback to basic auth is supported, but only when using <login-config>, which delegates to server user registries.

Is there any other way to achieve that?

utle commented 4 years ago

Hi @ggam, no.

c-koell commented 3 years ago

We had the same issue and unfortionally we got also the answer that it works as designed. https://github.com/OpenLiberty/open-liberty/issues/11058

I think it is not the best solution because if you use a HttpAutenticationMechanism features like mpJwt and social logins does not work anymore ....