KEYCLOAK-861 Support basic authentication against user credentials managed by KeyCloak.
This commit is contained in:
parent
3e8495f435
commit
8e01f8ecf1
31 changed files with 644 additions and 28 deletions
|
@ -16,7 +16,7 @@ import java.util.Map;
|
|||
"resource", "public-client", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
"expose-token", "bearer-only"})
|
||||
"expose-token", "bearer-only", "enable-basic-auth"})
|
||||
public class BaseAdapterConfig extends BaseRealmConfig {
|
||||
@JsonProperty("resource")
|
||||
protected String resource;
|
||||
|
@ -34,6 +34,8 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
|||
protected boolean exposeToken;
|
||||
@JsonProperty("bearer-only")
|
||||
protected boolean bearerOnly;
|
||||
@JsonProperty("enable-basic-auth")
|
||||
protected boolean enableBasicAuth;
|
||||
@JsonProperty("public-client")
|
||||
protected boolean publicClient;
|
||||
@JsonProperty("credentials")
|
||||
|
@ -97,12 +99,20 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
|||
}
|
||||
|
||||
public boolean isBearerOnly() {
|
||||
return bearerOnly;
|
||||
}
|
||||
return bearerOnly;
|
||||
}
|
||||
|
||||
public void setBearerOnly(boolean bearerOnly) {
|
||||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
|
||||
public boolean isEnableBasicAuth() {
|
||||
return enableBasicAuth;
|
||||
}
|
||||
|
||||
public void setEnableBasicAuth(boolean enableBasicAuth) {
|
||||
this.enableBasicAuth = enableBasicAuth;
|
||||
}
|
||||
|
||||
public Map<String, String> getCredentials() {
|
||||
return credentials;
|
||||
|
|
|
@ -50,6 +50,14 @@
|
|||
<exclude name="**/subsystem-config.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/basic-auth" overwrite="true">
|
||||
<fileset dir="../../examples/basic-auth">
|
||||
<exclude name="**/target/**"/>
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/admin-client" overwrite="true">
|
||||
<fileset dir="../../examples/admin-client">
|
||||
<exclude name="**/target/**"/>
|
||||
|
|
|
@ -86,9 +86,6 @@
|
|||
<module-def name="org.keycloak.keycloak-subsystem">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-subsystem"/>
|
||||
</module-def>
|
||||
<module-def name="org.keycloak.keycloak-as7-subsystem">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-as7-subsystem"/>
|
||||
</module-def>
|
||||
<module-def name="org.picketlink">
|
||||
</module-def>
|
||||
<module-def name="org.picketlink.common">
|
||||
|
|
|
@ -52,11 +52,6 @@
|
|||
<artifactId>keycloak-subsystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-as7-subsystem</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk16</artifactId>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
<module name="org.apache.httpcomponents" />
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="net.iharder.base64"/>
|
||||
</dependencies>
|
||||
|
||||
</module>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"cors-max-age" : 1000,
|
||||
"cors-allowed-methods" : [ "POST", "PUT", "DELETE", "GET" ],
|
||||
"bearer-only" : false,
|
||||
"enable-basic-auth" : false,
|
||||
"expose-token" : true,
|
||||
"credentials" : {
|
||||
"secret" : "234234-234234-234234"
|
||||
|
@ -157,6 +158,16 @@
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>enable-basic-auth</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This tells the adapter to also support basic authentication. If this option is enabled,
|
||||
then <emphasis>secret</emphasis> must also be provided.
|
||||
This is <emphasis>OPTIONAL</emphasis>. The default value is <emphasis>false</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>expose-token</term>
|
||||
<listitem>
|
||||
|
|
29
examples/basic-auth/README.md
Normal file
29
examples/basic-auth/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
Keycloak Example - Basic Authentication
|
||||
=======================================
|
||||
|
||||
The following example was tested on Wildfly 8.1.0.Final and JBoss EAP 6.3. It should be compatible with any JBoss AS, JBoss EAP or Wildfly that supports Java EE 7.
|
||||
|
||||
This example demonstrates basic authentication support for a Keycloak protected REST service. However, more importantly it enables a REST service to be secured using both basic and bearer token authentication, which is useful where the service needs to be accessed both as part of a single signon session, and also as a standalone REST service.
|
||||
|
||||
|
||||
Step 1: Setup a basic Keycloak server
|
||||
--------------------------------------------------------------
|
||||
Install Keycloak server and start it on port 8080. Check the Reference Guide if unsure on how to do it.
|
||||
|
||||
Once the Keycloak server is up and running, import the realm basicauthrealm.json.
|
||||
|
||||
|
||||
Step 2: Deploy and run the example
|
||||
--------------------------------------------------------------
|
||||
|
||||
- Build and deploy this sample's WAR file. For this example, deploy on the same server that is running the Keycloak Server, although this is not required for real world scenarios.
|
||||
|
||||
- Open a command window and perform the following command:
|
||||
|
||||
curl http://admin:password@localhost:8080/basicauth/service/echo?value=hello
|
||||
|
||||
This should result in the value 'hello' being returned as a response.
|
||||
|
||||
Simply change the username (currently 'admin') or password (currently 'password') in the command to see an "Unauthorized" response.
|
||||
|
||||
|
56
examples/basic-auth/basicauthrealm.json
Normal file
56
examples/basic-auth/basicauthrealm.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"realm": "basic-auth",
|
||||
"enabled": true,
|
||||
"accessTokenLifespan": 60,
|
||||
"accessCodeLifespan": 60,
|
||||
"accessCodeLifespanUserAction": 300,
|
||||
"ssoSessionIdleTimeout": 600,
|
||||
"ssoSessionMaxLifespan": 36000,
|
||||
"passwordCredentialGrantAllowed": true,
|
||||
"sslRequired": "external",
|
||||
"registrationAllowed": false,
|
||||
"social": false,
|
||||
"updateProfileOnInitialSocialLogin": false,
|
||||
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"requiredCredentials": [ "password" ],
|
||||
"users" : [
|
||||
{
|
||||
"username" : "admin",
|
||||
"enabled": true,
|
||||
"email" : "admin@admin.com",
|
||||
"firstName": "Admin",
|
||||
"lastName": "Burke",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
],
|
||||
"realmRoles": [ "user","admin" ],
|
||||
"applicationRoles": {
|
||||
"realm-management": [ "realm-admin" ]
|
||||
}
|
||||
}
|
||||
],
|
||||
"roles" : {
|
||||
"realm" : [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator privileges"
|
||||
}
|
||||
]
|
||||
},
|
||||
"applications": [
|
||||
{
|
||||
"name": "basic-auth-service",
|
||||
"enabled": true,
|
||||
"adminUrl": "/basicauth",
|
||||
"baseUrl": "/basicauth",
|
||||
"secret": "password"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
94
examples/basic-auth/pom.xml
Normal file
94
examples/basic-auth/pom.xml
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.1.0.Beta2-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Keycloak Examples - Basic Auth</name>
|
||||
<artifactId>examples-basicauth</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<description>
|
||||
Keycloak Basic Auth Example
|
||||
</description>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss</id>
|
||||
<name>jboss repo</name>
|
||||
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-adapter-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${keycloak.apache.httpcomponents.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>basicauth</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jboss.as.plugins</groupId>
|
||||
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.wildfly.plugins</groupId>
|
||||
<artifactId>wildfly-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,24 @@
|
|||
package org.keycloak.example.basicauth;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Path("service")
|
||||
public class BasicAuthService {
|
||||
@GET
|
||||
@NoCache
|
||||
@Path("echo")
|
||||
public String echo(@QueryParam("value") String value) {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.keycloak.example.basicauth;
|
||||
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
|
||||
/**
|
||||
* Basic auth app.
|
||||
*/
|
||||
@ApplicationPath("/")
|
||||
public class BasicAuthServiceApplication extends Application
|
||||
{
|
||||
}
|
11
examples/basic-auth/src/main/webapp/WEB-INF/keycloak.json
Normal file
11
examples/basic-auth/src/main/webapp/WEB-INF/keycloak.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"realm" : "basic-auth",
|
||||
"resource" : "basic-auth-service",
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url": "/auth",
|
||||
"ssl-required" : "external",
|
||||
"enable-basic-auth" : "true",
|
||||
"credentials": {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
29
examples/basic-auth/src/main/webapp/WEB-INF/web.xml
Normal file
29
examples/basic-auth/src/main/webapp/WEB-INF/web.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<module-name>basicauth</module-name>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<!-- <user-data-constraint>
|
||||
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
|
||||
</user-data-constraint> -->
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>KEYCLOAK</auth-method>
|
||||
<realm-name>basic-auth</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -31,5 +31,6 @@
|
|||
<module>providers</module>
|
||||
<module>js-console</module>
|
||||
<module>multi-tenant</module>
|
||||
<module>basic-auth</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
<artifactId>jackson-xc</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.iharder</groupId>
|
||||
<artifactId>base64</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
|
@ -237,6 +237,16 @@ public class AdapterDeploymentContext {
|
|||
delegate.setBearerOnly(bearerOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableBasicAuth() {
|
||||
return delegate.isEnableBasicAuth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnableBasicAuth(boolean enableBasicAuth) {
|
||||
delegate.setEnableBasicAuth(enableBasicAuth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublicClient() {
|
||||
return delegate.isPublicClient();
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package org.keycloak.adapters;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.constants.ServiceUrlConstants;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.util.BasicAuthHelper;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.KeycloakUriBuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Basic auth request authenticator.
|
||||
*/
|
||||
public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticator {
|
||||
protected Logger log = Logger.getLogger(BasicAuthRequestAuthenticator.class);
|
||||
|
||||
public BasicAuthRequestAuthenticator(KeycloakDeployment deployment) {
|
||||
super(deployment);
|
||||
}
|
||||
|
||||
public AuthOutcome authenticate(HttpFacade exchange) {
|
||||
List<String> authHeaders = exchange.getRequest().getHeaders("Authorization");
|
||||
if (authHeaders == null || authHeaders.size() == 0) {
|
||||
challenge = challengeResponse(exchange, null, null);
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
tokenString = null;
|
||||
for (String authHeader : authHeaders) {
|
||||
String[] split = authHeader.trim().split("\\s+");
|
||||
if (split == null || split.length != 2) continue;
|
||||
if (!split[0].equalsIgnoreCase("Basic")) continue;
|
||||
tokenString = split[1];
|
||||
}
|
||||
|
||||
if (tokenString == null) {
|
||||
challenge = challengeResponse(exchange, null, null);
|
||||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
AccessTokenResponse atr=null;
|
||||
try {
|
||||
String userpw=new String(net.iharder.Base64.decode(tokenString));
|
||||
String[] parts=userpw.split(":");
|
||||
|
||||
atr = getToken(parts[0], parts[1]);
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to obtain token", e);
|
||||
challenge = challengeResponse(exchange, "no_token", e.getMessage());
|
||||
return AuthOutcome.FAILED;
|
||||
}
|
||||
|
||||
return authenticateToken(exchange, atr.getToken());
|
||||
}
|
||||
|
||||
private AccessTokenResponse getToken(String username, String password) throws Exception {
|
||||
AccessTokenResponse tokenResponse=null;
|
||||
HttpClient client = new HttpClientBuilder().disableTrustManager().build();
|
||||
|
||||
try {
|
||||
HttpPost post = new HttpPost(
|
||||
KeycloakUriBuilder.fromUri(deployment.getAuthServerBaseUrl())
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_DIRECT_GRANT_PATH).build(deployment.getRealm()));
|
||||
java.util.List <NameValuePair> formparams = new java.util.ArrayList <NameValuePair>();
|
||||
formparams.add(new BasicNameValuePair("username", username));
|
||||
formparams.add(new BasicNameValuePair("password", password));
|
||||
|
||||
if (deployment.isPublicClient()) {
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, deployment.getResourceName()));
|
||||
} else {
|
||||
String authorization = BasicAuthHelper.createHeader(deployment.getResourceName(),
|
||||
deployment.getResourceCredentials().get("secret"));
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
post.setEntity(form);
|
||||
|
||||
HttpResponse response = client.execute(post);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (status != 200) {
|
||||
throw new java.io.IOException("Bad status: " + status);
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new java.io.IOException("No Entity");
|
||||
}
|
||||
java.io.InputStream is = entity.getContent();
|
||||
try {
|
||||
tokenResponse = JsonSerialization.readValue(is, AccessTokenResponse.class);
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (java.io.IOException ignored) { }
|
||||
}
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
|
||||
return (tokenResponse);
|
||||
}
|
||||
|
||||
}
|
|
@ -59,6 +59,10 @@ public class BearerTokenRequestAuthenticator {
|
|||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
return (authenticateToken(exchange, tokenString));
|
||||
}
|
||||
|
||||
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
|
||||
try {
|
||||
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
|
||||
} catch (VerificationException e) {
|
||||
|
|
|
@ -38,6 +38,7 @@ public class KeycloakDeployment {
|
|||
|
||||
protected String resourceName;
|
||||
protected boolean bearerOnly;
|
||||
protected boolean enableBasicAuth;
|
||||
protected boolean publicClient;
|
||||
protected Map<String, String> resourceCredentials = new HashMap<String, String>();
|
||||
protected HttpClient client;
|
||||
|
@ -199,6 +200,14 @@ public class KeycloakDeployment {
|
|||
this.bearerOnly = bearerOnly;
|
||||
}
|
||||
|
||||
public boolean isEnableBasicAuth() {
|
||||
return enableBasicAuth;
|
||||
}
|
||||
|
||||
public void setEnableBasicAuth(boolean enableBasicAuth) {
|
||||
this.enableBasicAuth = enableBasicAuth;
|
||||
}
|
||||
|
||||
public boolean isPublicClient() {
|
||||
return publicClient;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ public class KeycloakDeploymentBuilder {
|
|||
}
|
||||
|
||||
deployment.setBearerOnly(adapterConfig.isBearerOnly());
|
||||
deployment.setEnableBasicAuth(adapterConfig.isEnableBasicAuth());
|
||||
deployment.setAlwaysRefreshToken(adapterConfig.isAlwaysRefreshToken());
|
||||
deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
|
||||
deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
|
||||
|
|
|
@ -36,10 +36,12 @@ public abstract class RequestAuthenticator {
|
|||
if (log.isTraceEnabled()) {
|
||||
log.trace("--> authenticate()");
|
||||
}
|
||||
|
||||
BearerTokenRequestAuthenticator bearer = createBearerTokenAuthenticator();
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("try bearer");
|
||||
}
|
||||
|
||||
AuthOutcome outcome = bearer.authenticate(facade);
|
||||
if (outcome == AuthOutcome.FAILED) {
|
||||
challenge = bearer.getChallenge();
|
||||
|
@ -47,7 +49,7 @@ public abstract class RequestAuthenticator {
|
|||
return AuthOutcome.FAILED;
|
||||
} else if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
if (verifySSL()) return AuthOutcome.FAILED;
|
||||
completeAuthentication(bearer);
|
||||
completeAuthentication(bearer, "KEYCLOAK");
|
||||
log.debug("Bearer AUTHENTICATED");
|
||||
return AuthOutcome.AUTHENTICATED;
|
||||
} else if (deployment.isBearerOnly()) {
|
||||
|
@ -56,6 +58,24 @@ public abstract class RequestAuthenticator {
|
|||
return AuthOutcome.NOT_ATTEMPTED;
|
||||
}
|
||||
|
||||
if (deployment.isEnableBasicAuth()) {
|
||||
BasicAuthRequestAuthenticator basicAuth = createBasicAuthAuthenticator();
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("try basic auth");
|
||||
}
|
||||
|
||||
outcome = basicAuth.authenticate(facade);
|
||||
if (outcome == AuthOutcome.FAILED) {
|
||||
challenge = basicAuth.getChallenge();
|
||||
log.debug("BasicAuth FAILED");
|
||||
return AuthOutcome.FAILED;
|
||||
} else if (outcome == AuthOutcome.AUTHENTICATED) {
|
||||
log.debug("BasicAuth AUTHENTICATED");
|
||||
completeAuthentication(basicAuth, "BASIC");
|
||||
return AuthOutcome.AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("try oauth");
|
||||
}
|
||||
|
@ -104,6 +124,10 @@ public abstract class RequestAuthenticator {
|
|||
return new BearerTokenRequestAuthenticator(deployment);
|
||||
}
|
||||
|
||||
protected BasicAuthRequestAuthenticator createBasicAuthAuthenticator() {
|
||||
return new BasicAuthRequestAuthenticator(deployment);
|
||||
}
|
||||
|
||||
protected void completeAuthentication(OAuthRequestAuthenticator oauth) {
|
||||
RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, tokenStore, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken());
|
||||
final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(AdapterUtils.getPrincipalName(deployment, oauth.getToken()), session);
|
||||
|
@ -111,13 +135,13 @@ public abstract class RequestAuthenticator {
|
|||
}
|
||||
|
||||
protected abstract void completeOAuthAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
|
||||
protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
|
||||
protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method);
|
||||
protected abstract String getHttpSessionId(boolean create);
|
||||
|
||||
protected void completeAuthentication(BearerTokenRequestAuthenticator bearer) {
|
||||
protected void completeAuthentication(BearerTokenRequestAuthenticator bearer, String method) {
|
||||
RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, null, bearer.getTokenString(), bearer.getToken(), null, null, null);
|
||||
final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(AdapterUtils.getPrincipalName(deployment, bearer.getToken()), session);
|
||||
completeBearerAuthentication(principal);
|
||||
completeBearerAuthentication(principal, method);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
if (log.isDebugEnabled()) {
|
||||
|
@ -92,7 +92,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
|||
}
|
||||
Principal generalPrincipal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), principal, roles, securityContext);
|
||||
request.setUserPrincipal(generalPrincipal);
|
||||
request.setAuthType("KEYCLOAK");
|
||||
request.setAuthType(method);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.keycloak.adapters.AdapterUtils;
|
|||
import org.keycloak.adapters.AuthChallenge;
|
||||
import org.keycloak.adapters.AuthOutcome;
|
||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||
import org.keycloak.adapters.BasicAuthRequestAuthenticator;
|
||||
import org.keycloak.adapters.BearerTokenRequestAuthenticator;
|
||||
import org.keycloak.adapters.KeycloakConfigResolver;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
|
@ -188,10 +189,16 @@ public class JaxrsBearerTokenFilterImpl implements JaxrsBearerTokenFilter {
|
|||
}
|
||||
|
||||
protected void bearerAuthentication(JaxrsHttpFacade facade, ContainerRequestContext request, KeycloakDeployment resolvedDeployment) {
|
||||
BearerTokenRequestAuthenticator bearer = new BearerTokenRequestAuthenticator(resolvedDeployment);
|
||||
AuthOutcome outcome = bearer.authenticate(facade);
|
||||
BearerTokenRequestAuthenticator authenticator = new BearerTokenRequestAuthenticator(resolvedDeployment);
|
||||
AuthOutcome outcome = authenticator.authenticate(facade);
|
||||
|
||||
if (outcome == AuthOutcome.NOT_ATTEMPTED && resolvedDeployment.isEnableBasicAuth()) {
|
||||
authenticator = new BasicAuthRequestAuthenticator(resolvedDeployment);
|
||||
outcome = authenticator.authenticate(facade);
|
||||
}
|
||||
|
||||
if (outcome == AuthOutcome.FAILED || outcome == AuthOutcome.NOT_ATTEMPTED) {
|
||||
AuthChallenge challenge = bearer.getChallenge();
|
||||
AuthChallenge challenge = authenticator.getChallenge();
|
||||
log.fine("Authentication outcome: " + outcome);
|
||||
boolean challengeSent = challenge.challenge(facade);
|
||||
if (!challengeSent) {
|
||||
|
@ -210,7 +217,7 @@ public class JaxrsBearerTokenFilterImpl implements JaxrsBearerTokenFilter {
|
|||
}
|
||||
}
|
||||
|
||||
propagateSecurityContext(facade, request, resolvedDeployment, bearer);
|
||||
propagateSecurityContext(facade, request, resolvedDeployment, authenticator);
|
||||
handleAuthActions(facade, resolvedDeployment);
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ public abstract class AbstractJettyRequestAuthenticator extends RequestAuthentic
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
this.principal = principal;
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
|
|
|
@ -65,6 +65,12 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
|||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
|
||||
new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
|
||||
.setXmlName("enable-basic-auth")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
|
||||
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
|
||||
.setXmlName("public-client")
|
||||
|
@ -78,6 +84,7 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
|
|||
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
|
||||
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ keycloak.secure-deployment.resource=Application name
|
|||
keycloak.secure-deployment.use-resource-role-mappings=Use resource level permissions from token
|
||||
keycloak.secure-deployment.credentials=Adapter credentials
|
||||
keycloak.secure-deployment.bearer-only=Bearer Token Auth only
|
||||
keycloak.secure-deployment.enable-basic-auth=Enable Basic Authentication
|
||||
keycloak.secure-deployment.public-client=Public client
|
||||
keycloak.secure-deployment.enable-cors=Enable Keycloak CORS support
|
||||
keycloak.secure-deployment.client-keystore=n/a
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="enable-basic-auth" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
|
|
@ -86,7 +86,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
RefreshableKeycloakSecurityContext securityContext = principal.getKeycloakSecurityContext();
|
||||
Set<String> roles = AdapterUtils.getRolesFromSecurityContext(securityContext);
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
|
@ -94,7 +94,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
|
|||
}
|
||||
Principal generalPrincipal = principalFactory.createPrincipal(request.getContext().getRealm(), principal, roles, securityContext);
|
||||
request.setUserPrincipal(generalPrincipal);
|
||||
request.setAuthType("KEYCLOAK");
|
||||
request.setAuthType(method);
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import io.undertow.security.api.SecurityContext;
|
|||
import io.undertow.server.HttpServerExchange;
|
||||
import io.undertow.server.session.Session;
|
||||
import io.undertow.util.Sessions;
|
||||
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.AdapterTokenStore;
|
||||
import org.keycloak.adapters.HttpFacade;
|
||||
|
@ -69,9 +70,9 @@ public abstract class AbstractUndertowRequestAuthenticator extends RequestAuthen
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
|
||||
protected void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method) {
|
||||
KeycloakUndertowAccount account = createAccount(principal);
|
||||
securityContext.authenticationComplete(account, "KEYCLOAK", false);
|
||||
securityContext.authenticationComplete(account, method, false);
|
||||
propagateKeycloakContext(account);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
package org.keycloak.testsuite.jaxrs;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.keycloak.adapters.HttpClientBuilder;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.Constants;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
/**
|
||||
* Test for basic authentication.
|
||||
*/
|
||||
public class JaxrsBasicAuthTest {
|
||||
|
||||
private static final String JAXRS_APP_URL = Constants.SERVER_ROOT + "/jaxrs-simple/res";
|
||||
|
||||
public static final String CONFIG_FILE_INIT_PARAM = "config-file";
|
||||
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ApplicationModel app = appRealm.addApplication("jaxrs-app");
|
||||
app.setEnabled(true);
|
||||
app.setSecret("password");
|
||||
|
||||
JaxrsBasicAuthTest.appRealm = appRealm;
|
||||
}
|
||||
});
|
||||
|
||||
@ClassRule
|
||||
public static ExternalResource clientRule = new ExternalResource() {
|
||||
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
|
||||
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
|
||||
client = new ResteasyClientBuilder().httpEngine(engine).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
client.close();
|
||||
}
|
||||
};
|
||||
|
||||
private static ResteasyClient client;
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
||||
@WebResource
|
||||
protected WebDriver driver;
|
||||
|
||||
// Used for signing admin action
|
||||
protected static RealmModel appRealm;
|
||||
|
||||
|
||||
@Test
|
||||
public void testBasic() {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
Map<String,String> initParams = new TreeMap<String,String>();
|
||||
initParams.put(CONFIG_FILE_INIT_PARAM, "classpath:jaxrs-test/jaxrs-keycloak-basicauth.json");
|
||||
keycloakRule.deployJaxrsApplication("JaxrsSimpleApp", "/jaxrs-simple", JaxrsTestApplication.class, initParams);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Send GET request without credentials, it should fail
|
||||
Response getResp = client.target(JAXRS_APP_URL).request().get();
|
||||
Assert.assertEquals(getResp.getStatus(), 401);
|
||||
getResp.close();
|
||||
|
||||
// Send POST request without credentials, it should fail
|
||||
Response postResp = client.target(JAXRS_APP_URL).request().post(Entity.form(new Form()));
|
||||
Assert.assertEquals(postResp.getStatus(), 401);
|
||||
postResp.close();
|
||||
|
||||
// Retrieve token
|
||||
String incorrectAuthHeader = "Basic "+encodeCredentials("invalid-user", "password");
|
||||
|
||||
// Send GET request with incorrect credentials, it shojuld fail
|
||||
getResp = client.target(JAXRS_APP_URL).request()
|
||||
.header(HttpHeaders.AUTHORIZATION, incorrectAuthHeader)
|
||||
.get();
|
||||
Assert.assertEquals(getResp.getStatus(), 401);
|
||||
getResp.close();
|
||||
|
||||
// Retrieve token
|
||||
String authHeader = "Basic "+encodeCredentials("test-user@localhost", "password");
|
||||
|
||||
// Send GET request with token and assert it's passing
|
||||
JaxrsTestResource.SimpleRepresentation getRep = client.target(JAXRS_APP_URL).request()
|
||||
.header(HttpHeaders.AUTHORIZATION, authHeader)
|
||||
.get(JaxrsTestResource.SimpleRepresentation.class);
|
||||
Assert.assertEquals("get", getRep.getMethod());
|
||||
|
||||
// TODO: SHOULD HAVE USER ROLE
|
||||
//Assert.assertTrue(getRep.getHasUserRole());
|
||||
|
||||
Assert.assertFalse(getRep.getHasAdminRole());
|
||||
Assert.assertFalse(getRep.getHasJaxrsAppRole());
|
||||
// Assert that principal is ID of user (should be in UUID format)
|
||||
UUID.fromString(getRep.getPrincipal());
|
||||
|
||||
// Send POST request with token and assert it's passing
|
||||
JaxrsTestResource.SimpleRepresentation postRep = client.target(JAXRS_APP_URL).request()
|
||||
.header(HttpHeaders.AUTHORIZATION, authHeader)
|
||||
.post(Entity.form(new Form()), JaxrsTestResource.SimpleRepresentation.class);
|
||||
Assert.assertEquals("post", postRep.getMethod());
|
||||
Assert.assertEquals(getRep.getPrincipal(), postRep.getPrincipal());
|
||||
}
|
||||
|
||||
private String encodeCredentials(String username, String password) {
|
||||
String text=username+":"+password;
|
||||
return (net.iharder.Base64.encodeBytes(text.getBytes()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"realm": "test",
|
||||
"resource": "jaxrs-app",
|
||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url": "http://localhost:8081/auth",
|
||||
"ssl-required" : "external",
|
||||
"enable-basic-auth": true,
|
||||
"credentials": {
|
||||
"secret": "password"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue