/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.rest.resource;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.keycloak.OAuth2Constants;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.jose.jwk.JWKBuilder;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.testsuite.rest.TestApplicationResourceProviderFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class TestingOIDCEndpointsApplicationResource {
public static final String PRIVATE_KEY = "privateKey";
public static final String PUBLIC_KEY = "publicKey";
private final TestApplicationResourceProviderFactory.OIDCClientData clientData;
public TestingOIDCEndpointsApplicationResource(TestApplicationResourceProviderFactory.OIDCClientData oidcClientData) {
this.clientData = oidcClientData;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/generate-keys")
@NoCache
public Map<String, String> generateKeys() {
try {
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
clientData.setSigningKeyPair(keyPair);
} catch (Exception e) {
throw new BadRequestException("Error generating signing keypair", e);
}
return getKeysAsPem();
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/get-keys-as-pem")
public Map<String, String> getKeysAsPem() {
String privateKeyPem = PemUtils.encodeKey(clientData.getSigningKeyPair().getPrivate());
String publicKeyPem = PemUtils.encodeKey(clientData.getSigningKeyPair().getPublic());
Map<String, String> res = new HashMap<>();
res.put(PRIVATE_KEY, privateKeyPem);
res.put(PUBLIC_KEY, publicKeyPem);
return res;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/get-jwks")
@NoCache
public JSONWebKeySet getJwks() {
JSONWebKeySet keySet = new JSONWebKeySet();
if (clientData.getSigningKeyPair() == null) {
keySet.setKeys(new JWK[] {});
} else {
keySet.setKeys(new JWK[] { JWKBuilder.create().rs256(clientData.getSigningKeyPair().getPublic()) });
}
return keySet;
}
@GET
@Path("/set-oidc-request")
@Produces(org.keycloak.utils.MediaType.APPLICATION_JWT)
@NoCache
public void setOIDCRequest(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId,
@QueryParam("redirectUri") String redirectUri, @QueryParam("maxAge") String maxAge,
@QueryParam("jwaAlgorithm") String jwaAlgorithm) {
Map<String, Object> oidcRequest = new HashMap<>();
oidcRequest.put(OIDCLoginProtocol.CLIENT_ID_PARAM, clientId);
oidcRequest.put(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE);
oidcRequest.put(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri);
if (maxAge != null) {
oidcRequest.put(OIDCLoginProtocol.MAX_AGE_PARAM, Integer.parseInt(maxAge));
}
Algorithm alg = Enum.valueOf(Algorithm.class, jwaAlgorithm);
if (alg == Algorithm.none) {
clientData.setOidcRequest(new JWSBuilder().jsonContent(oidcRequest).none());
} else if (alg == Algorithm.RS256) {
if (clientData.getSigningKeyPair() == null) {
throw new BadRequestException("Requested RS256, but signing key not set");
}
PrivateKey privateKey = clientData.getSigningKeyPair().getPrivate();
String kid = KeyUtils.createKeyId(clientData.getSigningKeyPair().getPublic());
clientData.setOidcRequest(new JWSBuilder().kid(kid).jsonContent(oidcRequest).rsa256(privateKey));
} else {
throw new BadRequestException("Unknown argument: " + jwaAlgorithm);
}
}
@GET
@Path("/get-oidc-request")
@Produces(org.keycloak.utils.MediaType.APPLICATION_JWT)
@NoCache
public String getOIDCRequest() {
return clientData.getOidcRequest();
}
@GET
@Path("/set-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
public void setSectorIdentifierRedirectUris(@QueryParam("redirectUris") List<String> redirectUris) {
clientData.setSectorIdentifierRedirectUris(new ArrayList<>());
clientData.getSectorIdentifierRedirectUris().addAll(redirectUris);
}
@GET
@Path("/get-sector-identifier-redirect-uris")
@Produces(MediaType.APPLICATION_JSON)
public List<String> getSectorIdentifierRedirectUris() {
return clientData.getSectorIdentifierRedirectUris();
}
}