Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 51A1A185C8 for ; Tue, 9 Feb 2016 10:36:38 +0000 (UTC) Received: (qmail 2989 invoked by uid 500); 9 Feb 2016 10:36:38 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 2932 invoked by uid 500); 9 Feb 2016 10:36:38 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 2921 invoked by uid 99); 9 Feb 2016 10:36:38 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Feb 2016 10:36:38 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 0B533E0099; Tue, 9 Feb 2016 10:36:38 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sergeyb@apache.org To: commits@cxf.apache.org Message-Id: <789630f05ee5463697661b982937aee9@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: cxf-fediz git commit: Moving the code for manging client regs and tokens to a clients subpackage Date: Tue, 9 Feb 2016 10:36:38 +0000 (UTC) Repository: cxf-fediz Updated Branches: refs/heads/master 28dcba96a -> 6e1c0ddf7 Moving the code for manging client regs and tokens to a clients subpackage Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/6e1c0ddf Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/6e1c0ddf Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/6e1c0ddf Branch: refs/heads/master Commit: 6e1c0ddf76c39a5b223b47cbdb93d93e665ff1e8 Parents: 28dcba9 Author: Sergey Beryozkin Authored: Tue Feb 9 10:36:23 2016 +0000 Committer: Sergey Beryozkin Committed: Tue Feb 9 10:36:23 2016 +0000 ---------------------------------------------------------------------- .../fediz/service/oidc/ClientCodeGrants.java | 48 --- .../service/oidc/ClientRegistrationService.java | 378 ------------------- .../cxf/fediz/service/oidc/ClientTokens.java | 48 --- .../fediz/service/oidc/InvalidRegistration.java | 31 -- .../cxf/fediz/service/oidc/RegisterClient.java | 33 -- .../fediz/service/oidc/RegisteredClients.java | 35 -- .../service/oidc/clients/ClientCodeGrants.java | 48 +++ .../oidc/clients/ClientRegistrationService.java | 378 +++++++++++++++++++ .../service/oidc/clients/ClientTokens.java | 48 +++ .../oidc/clients/InvalidRegistration.java | 31 ++ .../service/oidc/clients/RegisterClient.java | 33 ++ .../service/oidc/clients/RegisteredClients.java | 35 ++ .../main/webapp/WEB-INF/applicationContext.xml | 5 +- .../webapp/WEB-INF/views/clientCodeGrants.jsp | 2 +- .../main/webapp/WEB-INF/views/clientTokens.jsp | 2 +- .../WEB-INF/views/invalidRegistration.jsp | 2 +- .../webapp/WEB-INF/views/registerClient.jsp | 2 +- .../webapp/WEB-INF/views/registeredClients.jsp | 2 +- 18 files changed, 581 insertions(+), 580 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientCodeGrants.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientCodeGrants.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientCodeGrants.java deleted file mode 100644 index 6134fcc..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientCodeGrants.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.cxf.rs.security.oauth2.common.Client; -import org.apache.cxf.rs.security.oauth2.grants.code.ServerAuthorizationCodeGrant; - -public class ClientCodeGrants { - private Client client; - private List codeGrants = new LinkedList(); - public ClientCodeGrants(Client c, List codeGrants) { - this.client = c; - this.setCodeGrants(codeGrants); - } - public Client getClient() { - return client; - } - public void setClient(Client client) { - this.client = client; - } - public List getCodeGrants() { - return codeGrants; - } - public void setCodeGrants(List codeGrants) { - this.codeGrants = codeGrants; - } - - -} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientRegistrationService.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientRegistrationService.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientRegistrationService.java deleted file mode 100644 index ad4e7a8..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientRegistrationService.java +++ /dev/null @@ -1,378 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.ws.rs.Consumes; -import javax.ws.rs.FormParam; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; - -import org.apache.commons.validator.routines.UrlValidator; -import org.apache.cxf.common.util.Base64UrlUtility; -import org.apache.cxf.common.util.StringUtils; -import org.apache.cxf.rs.security.oauth2.common.Client; -import org.apache.cxf.rs.security.oauth2.common.UserSubject; -import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeDataProvider; -import org.apache.cxf.rs.security.oauth2.provider.ClientRegistrationProvider; -import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider; -import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; -import org.apache.cxf.rt.security.crypto.CryptoUtils; - -@Path("/") -public class ClientRegistrationService { - - private Map> registrations = new ConcurrentHashMap>(); - private OAuthDataProvider dataProvider; - private ClientRegistrationProvider clientProvider; - private Map homeRealms = new LinkedHashMap(); - private boolean protectIdTokenWithClientSecret; - private Map clientScopes; - - @Context - private SecurityContext sc; - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("/register") - public RegisterClient registerStart() { - return new RegisterClient(homeRealms); - } - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("/") - public RegisteredClients getClients() { - return new RegisteredClients(getClientRegistrations()); - } - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("/{id}") - public Client getRegisteredClient(@PathParam("id") String id) { - for (Client c : getClientRegistrations()) { - if (c.getClientId().equals(id)) { - return c; - } - } - return null; - } - - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/remove") - public RegisteredClients removeClient(@PathParam("id") String id) { - Collection clients = getClientRegistrations(); - for (Iterator it = clients.iterator(); it.hasNext();) { - Client c = it.next(); - if (c.getClientId().equals(id)) { - clientProvider.removeClient(id); - it.remove(); - break; - } - } - return new RegisteredClients(clients); - } - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/reset") - public Client resetClient(@PathParam("id") String id) { - Client c = getRegisteredClient(id); - if (c.isConfidential()) { - c.setClientSecret(generateClientSecret()); - } - clientProvider.setClient(c); - return c; - } - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/tokens") - public ClientTokens getClientIssuedTokens(@PathParam("id") String id) { - Client c = getRegisteredClient(id); - return doGetClientIssuedTokens(c); - } - - protected ClientTokens doGetClientIssuedTokens(Client c) { - // Right now the user who is registering the clients - // is the one who is working with them, i.e, client registrations - // are user specific, so passing null is OK - return new ClientTokens(c, - dataProvider.getAccessTokens(c, null), - dataProvider.getRefreshTokens(c, null)); - } - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/at/{tokenId}/revoke") - public ClientTokens revokeClientAccessToken(@PathParam("id") String clientId, - @PathParam("tokenId") String tokenId) { - return doRevokeClientToken(clientId, tokenId, OAuthConstants.ACCESS_TOKEN); - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/rt/{tokenId}/revoke") - public ClientTokens revokeClientRefreshToken(@PathParam("id") String clientId, - @PathParam("tokenId") String tokenId) { - return doRevokeClientToken(clientId, tokenId, OAuthConstants.REFRESH_TOKEN); - } - - protected ClientTokens doRevokeClientToken(String clientId, - String tokenId, - String tokenType) { - Client c = getRegisteredClient(clientId); - dataProvider.revokeToken(c, tokenId, tokenType); - return doGetClientIssuedTokens(c); - } - - @GET - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/codes") - public ClientCodeGrants getClientCodeGrants(@PathParam("id") String id) { - if (dataProvider instanceof AuthorizationCodeDataProvider) { - Client c = getRegisteredClient(id); - return new ClientCodeGrants(c, - ((AuthorizationCodeDataProvider)dataProvider).getCodeGrants(c, null)); - } - return null; - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/{id}/codes/{code}/revoke") - public ClientCodeGrants revokeClientCodeGrant(@PathParam("id") String id, - @PathParam("code") String code) { - if (dataProvider instanceof AuthorizationCodeDataProvider) { - ((AuthorizationCodeDataProvider)dataProvider).removeCodeGrant(code); - return getClientCodeGrants(id); - } - return null; - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_HTML) - @Path("/") - public Response registerForm(@FormParam("client_name") String appName, - @FormParam("client_type") String appType, - @FormParam("client_audience") String audience, - @FormParam("client_redirectURI") String redirectURI, - @FormParam("client_homeRealm") String homeRealm - ) { - - // Client Name - if (StringUtils.isEmpty(appName)) { - return invalidRegistrationResponse("The client name must not be empty"); - } - // Client Type - if (StringUtils.isEmpty(appType)) { - return invalidRegistrationResponse("The client type must not be empty"); - } - if (!("confidential".equals(appType) || "public".equals(appType))) { - return invalidRegistrationResponse("An invalid client type was specified: " + appType); - } - // Client ID - String clientId = generateClientId(); - boolean isConfidential = "confidential".equals(appType); - // Client Secret - String clientSecret = isConfidential - ? generateClientSecret() - : null; - - Client newClient = new Client(clientId, clientSecret, isConfidential, appName); - - // User who registered this client - String userName = sc.getUserPrincipal().getName(); - UserSubject userSubject = new UserSubject(userName); - newClient.setResourceOwnerSubject(userSubject); - - // Client Registration Time - newClient.setRegisteredAt(System.currentTimeMillis() / 1000); - - // Client Realm - newClient.setHomeRealm(homeRealm); - - // Client Redirect URIs - if (!StringUtils.isEmpty(redirectURI)) { - String[] allUris = redirectURI.trim().split(" "); - List redirectUris = new LinkedList(); - for (String uri : allUris) { - if (!StringUtils.isEmpty(uri)) { - if (!isValidURI(uri, false)) { - return invalidRegistrationResponse("An invalid redirect URI was specified: " + uri); - } - redirectUris.add(uri); - } - } - newClient.setRedirectUris(redirectUris); - } - - // Client Audience URIs - if (!StringUtils.isEmpty(audience)) { - String[] auds = audience.trim().split(" "); - List registeredAuds = new LinkedList(); - for (String aud : auds) { - if (!StringUtils.isEmpty(aud)) { - if (!isValidURI(aud, true)) { - return invalidRegistrationResponse("An invalid audience URI was specified: " + aud); - } - registeredAuds.add(aud); - } - } - newClient.setRegisteredAudiences(registeredAuds); - } - - // Client Scopes - if (clientScopes != null && !clientScopes.isEmpty()) { - newClient.setRegisteredScopes(new ArrayList(clientScopes.keySet())); - } - - return Response.ok(registerNewClient(newClient)).build(); - } - - private Response invalidRegistrationResponse(String error) { - return Response.ok(new InvalidRegistration(error)).build(); - } - - private boolean isValidURI(String uri, boolean requireHttps) { - - UrlValidator urlValidator = null; - - if (requireHttps) { - String[] schemes = {"https"}; - urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS); - } else { - urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS - + UrlValidator.ALLOW_ALL_SCHEMES); - } - - if (!urlValidator.isValid(uri)) { - return false; - } - - // Do additional checks on the URI - try { - URI parsedURI = new URI(uri); - // The URI can't have a fragment according to the OAuth 2.0 spec (+ audience spec) - if (parsedURI.getFragment() != null) { - return false; - } - } catch (URISyntaxException ex) { - return false; - } - - return true; - } - - protected String generateClientId() { - return Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(10)); - } - - protected String generateClientSecret() { - // TODO: may need to be 384/8 or 512/8 if not a default HS256 but HS384 or HS512 - int keySizeOctets = protectIdTokenWithClientSecret - ? 32 - : 16; - return Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(keySizeOctets)); - } - - protected RegisteredClients registerNewClient(Client newClient) { - clientProvider.setClient(newClient); - Collection clientRegistrations = getClientRegistrations(); - clientRegistrations.add(newClient); - return new RegisteredClients(clientRegistrations); - } - - protected Collection getClientRegistrations() { - String userName = getUserName(); - return getClientRegistrations(userName); - } - - protected Collection getClientRegistrations(String userName) { - Collection userClientRegs = registrations.get(userName); - if (userClientRegs == null) { - userClientRegs = new HashSet(); - registrations.put(userName, userClientRegs); - } - return userClientRegs; - } - - private String getUserName() { - if (sc == null || sc.getUserPrincipal() == null) { - return null; - } - return sc.getUserPrincipal().getName(); - } - - public void setHomeRealms(Map homeRealms) { - this.homeRealms = homeRealms; - } - - public void init() { - for (Client c : clientProvider.getClients(null)) { - String userName = c.getResourceOwnerSubject().getLogin(); - getClientRegistrations(userName).add(c); - } - } - - public void setProtectIdTokenWithClientSecret(boolean protectIdTokenWithClientSecret) { - this.protectIdTokenWithClientSecret = protectIdTokenWithClientSecret; - } - - public void setClientScopes(Map clientScopes) { - this.clientScopes = clientScopes; - } - - public OAuthDataProvider getDataProvider() { - return dataProvider; - } - - public void setDataProvider(OAuthDataProvider dataProvider) { - this.dataProvider = dataProvider; - } - - public void setClientProvider(ClientRegistrationProvider clientProvider) { - this.clientProvider = clientProvider; - } -} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientTokens.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientTokens.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientTokens.java deleted file mode 100644 index e7ad7f6..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/ClientTokens.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.cxf.rs.security.oauth2.common.Client; -import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken; -import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken; - -public class ClientTokens { - private Client client; - private List accessTokens = new LinkedList(); - private List refreshTokens = new LinkedList(); - public ClientTokens(Client c, - List accessTokens, - List refreshTokens) { - this.client = c; - this.accessTokens = accessTokens; - this.refreshTokens = refreshTokens; - } - public Client getClient() { - return client; - } - public List getAccessTokens() { - return accessTokens; - } - public List getRefreshTokens() { - return refreshTokens; - } -} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/InvalidRegistration.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/InvalidRegistration.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/InvalidRegistration.java deleted file mode 100644 index 31637a7..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/InvalidRegistration.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -public class InvalidRegistration { - private String message; - public InvalidRegistration(String message) { - this.message = message; - } - public String getMessage() { - return message; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisterClient.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisterClient.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisterClient.java deleted file mode 100644 index 9a3b0b2..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisterClient.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -import java.util.Map; - -public class RegisterClient { - private Map homeRealms; - public RegisterClient(Map homeRealms) { - this.homeRealms = homeRealms; - } - public Map getHomeRealms() { - return homeRealms; - } - - -} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisteredClients.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisteredClients.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisteredClients.java deleted file mode 100644 index dc30b27..0000000 --- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/RegisteredClients.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.cxf.fediz.service.oidc; - -import java.util.Collection; - -import org.apache.cxf.rs.security.oauth2.common.Client; - -public class RegisteredClients { - private Collection clients; - public RegisteredClients(Collection clients) { - this.clients = clients; - } - public Collection getClients() { - return clients; - } - - -} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientCodeGrants.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientCodeGrants.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientCodeGrants.java new file mode 100644 index 0000000..af2b45f --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientCodeGrants.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.cxf.rs.security.oauth2.common.Client; +import org.apache.cxf.rs.security.oauth2.grants.code.ServerAuthorizationCodeGrant; + +public class ClientCodeGrants { + private Client client; + private List codeGrants = new LinkedList(); + public ClientCodeGrants(Client c, List codeGrants) { + this.client = c; + this.setCodeGrants(codeGrants); + } + public Client getClient() { + return client; + } + public void setClient(Client client) { + this.client = client; + } + public List getCodeGrants() { + return codeGrants; + } + public void setCodeGrants(List codeGrants) { + this.codeGrants = codeGrants; + } + + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientRegistrationService.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientRegistrationService.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientRegistrationService.java new file mode 100644 index 0000000..f8eef3f --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientRegistrationService.java @@ -0,0 +1,378 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; + +import org.apache.commons.validator.routines.UrlValidator; +import org.apache.cxf.common.util.Base64UrlUtility; +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.rs.security.oauth2.common.Client; +import org.apache.cxf.rs.security.oauth2.common.UserSubject; +import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeDataProvider; +import org.apache.cxf.rs.security.oauth2.provider.ClientRegistrationProvider; +import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider; +import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; +import org.apache.cxf.rt.security.crypto.CryptoUtils; + +@Path("/") +public class ClientRegistrationService { + + private Map> registrations = new ConcurrentHashMap>(); + private OAuthDataProvider dataProvider; + private ClientRegistrationProvider clientProvider; + private Map homeRealms = new LinkedHashMap(); + private boolean protectIdTokenWithClientSecret; + private Map clientScopes; + + @Context + private SecurityContext sc; + + @GET + @Produces(MediaType.TEXT_HTML) + @Path("/register") + public RegisterClient registerStart() { + return new RegisterClient(homeRealms); + } + + @GET + @Produces(MediaType.TEXT_HTML) + @Path("/") + public RegisteredClients getClients() { + return new RegisteredClients(getClientRegistrations()); + } + + @GET + @Produces(MediaType.TEXT_HTML) + @Path("/{id}") + public Client getRegisteredClient(@PathParam("id") String id) { + for (Client c : getClientRegistrations()) { + if (c.getClientId().equals(id)) { + return c; + } + } + return null; + } + + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/remove") + public RegisteredClients removeClient(@PathParam("id") String id) { + Collection clients = getClientRegistrations(); + for (Iterator it = clients.iterator(); it.hasNext();) { + Client c = it.next(); + if (c.getClientId().equals(id)) { + clientProvider.removeClient(id); + it.remove(); + break; + } + } + return new RegisteredClients(clients); + } + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/reset") + public Client resetClient(@PathParam("id") String id) { + Client c = getRegisteredClient(id); + if (c.isConfidential()) { + c.setClientSecret(generateClientSecret()); + } + clientProvider.setClient(c); + return c; + } + + @GET + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/tokens") + public ClientTokens getClientIssuedTokens(@PathParam("id") String id) { + Client c = getRegisteredClient(id); + return doGetClientIssuedTokens(c); + } + + protected ClientTokens doGetClientIssuedTokens(Client c) { + // Right now the user who is registering the clients + // is the one who is working with them, i.e, client registrations + // are user specific, so passing null is OK + return new ClientTokens(c, + dataProvider.getAccessTokens(c, null), + dataProvider.getRefreshTokens(c, null)); + } + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/at/{tokenId}/revoke") + public ClientTokens revokeClientAccessToken(@PathParam("id") String clientId, + @PathParam("tokenId") String tokenId) { + return doRevokeClientToken(clientId, tokenId, OAuthConstants.ACCESS_TOKEN); + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/rt/{tokenId}/revoke") + public ClientTokens revokeClientRefreshToken(@PathParam("id") String clientId, + @PathParam("tokenId") String tokenId) { + return doRevokeClientToken(clientId, tokenId, OAuthConstants.REFRESH_TOKEN); + } + + protected ClientTokens doRevokeClientToken(String clientId, + String tokenId, + String tokenType) { + Client c = getRegisteredClient(clientId); + dataProvider.revokeToken(c, tokenId, tokenType); + return doGetClientIssuedTokens(c); + } + + @GET + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/codes") + public ClientCodeGrants getClientCodeGrants(@PathParam("id") String id) { + if (dataProvider instanceof AuthorizationCodeDataProvider) { + Client c = getRegisteredClient(id); + return new ClientCodeGrants(c, + ((AuthorizationCodeDataProvider)dataProvider).getCodeGrants(c, null)); + } + return null; + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/{id}/codes/{code}/revoke") + public ClientCodeGrants revokeClientCodeGrant(@PathParam("id") String id, + @PathParam("code") String code) { + if (dataProvider instanceof AuthorizationCodeDataProvider) { + ((AuthorizationCodeDataProvider)dataProvider).removeCodeGrant(code); + return getClientCodeGrants(id); + } + return null; + } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_HTML) + @Path("/") + public Response registerForm(@FormParam("client_name") String appName, + @FormParam("client_type") String appType, + @FormParam("client_audience") String audience, + @FormParam("client_redirectURI") String redirectURI, + @FormParam("client_homeRealm") String homeRealm + ) { + + // Client Name + if (StringUtils.isEmpty(appName)) { + return invalidRegistrationResponse("The client name must not be empty"); + } + // Client Type + if (StringUtils.isEmpty(appType)) { + return invalidRegistrationResponse("The client type must not be empty"); + } + if (!("confidential".equals(appType) || "public".equals(appType))) { + return invalidRegistrationResponse("An invalid client type was specified: " + appType); + } + // Client ID + String clientId = generateClientId(); + boolean isConfidential = "confidential".equals(appType); + // Client Secret + String clientSecret = isConfidential + ? generateClientSecret() + : null; + + Client newClient = new Client(clientId, clientSecret, isConfidential, appName); + + // User who registered this client + String userName = sc.getUserPrincipal().getName(); + UserSubject userSubject = new UserSubject(userName); + newClient.setResourceOwnerSubject(userSubject); + + // Client Registration Time + newClient.setRegisteredAt(System.currentTimeMillis() / 1000); + + // Client Realm + newClient.setHomeRealm(homeRealm); + + // Client Redirect URIs + if (!StringUtils.isEmpty(redirectURI)) { + String[] allUris = redirectURI.trim().split(" "); + List redirectUris = new LinkedList(); + for (String uri : allUris) { + if (!StringUtils.isEmpty(uri)) { + if (!isValidURI(uri, false)) { + return invalidRegistrationResponse("An invalid redirect URI was specified: " + uri); + } + redirectUris.add(uri); + } + } + newClient.setRedirectUris(redirectUris); + } + + // Client Audience URIs + if (!StringUtils.isEmpty(audience)) { + String[] auds = audience.trim().split(" "); + List registeredAuds = new LinkedList(); + for (String aud : auds) { + if (!StringUtils.isEmpty(aud)) { + if (!isValidURI(aud, true)) { + return invalidRegistrationResponse("An invalid audience URI was specified: " + aud); + } + registeredAuds.add(aud); + } + } + newClient.setRegisteredAudiences(registeredAuds); + } + + // Client Scopes + if (clientScopes != null && !clientScopes.isEmpty()) { + newClient.setRegisteredScopes(new ArrayList(clientScopes.keySet())); + } + + return Response.ok(registerNewClient(newClient)).build(); + } + + private Response invalidRegistrationResponse(String error) { + return Response.ok(new InvalidRegistration(error)).build(); + } + + private boolean isValidURI(String uri, boolean requireHttps) { + + UrlValidator urlValidator = null; + + if (requireHttps) { + String[] schemes = {"https"}; + urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS); + } else { + urlValidator = new UrlValidator(UrlValidator.ALLOW_LOCAL_URLS + + UrlValidator.ALLOW_ALL_SCHEMES); + } + + if (!urlValidator.isValid(uri)) { + return false; + } + + // Do additional checks on the URI + try { + URI parsedURI = new URI(uri); + // The URI can't have a fragment according to the OAuth 2.0 spec (+ audience spec) + if (parsedURI.getFragment() != null) { + return false; + } + } catch (URISyntaxException ex) { + return false; + } + + return true; + } + + protected String generateClientId() { + return Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(10)); + } + + protected String generateClientSecret() { + // TODO: may need to be 384/8 or 512/8 if not a default HS256 but HS384 or HS512 + int keySizeOctets = protectIdTokenWithClientSecret + ? 32 + : 16; + return Base64UrlUtility.encode(CryptoUtils.generateSecureRandomBytes(keySizeOctets)); + } + + protected RegisteredClients registerNewClient(Client newClient) { + clientProvider.setClient(newClient); + Collection clientRegistrations = getClientRegistrations(); + clientRegistrations.add(newClient); + return new RegisteredClients(clientRegistrations); + } + + protected Collection getClientRegistrations() { + String userName = getUserName(); + return getClientRegistrations(userName); + } + + protected Collection getClientRegistrations(String userName) { + Collection userClientRegs = registrations.get(userName); + if (userClientRegs == null) { + userClientRegs = new HashSet(); + registrations.put(userName, userClientRegs); + } + return userClientRegs; + } + + private String getUserName() { + if (sc == null || sc.getUserPrincipal() == null) { + return null; + } + return sc.getUserPrincipal().getName(); + } + + public void setHomeRealms(Map homeRealms) { + this.homeRealms = homeRealms; + } + + public void init() { + for (Client c : clientProvider.getClients(null)) { + String userName = c.getResourceOwnerSubject().getLogin(); + getClientRegistrations(userName).add(c); + } + } + + public void setProtectIdTokenWithClientSecret(boolean protectIdTokenWithClientSecret) { + this.protectIdTokenWithClientSecret = protectIdTokenWithClientSecret; + } + + public void setClientScopes(Map clientScopes) { + this.clientScopes = clientScopes; + } + + public OAuthDataProvider getDataProvider() { + return dataProvider; + } + + public void setDataProvider(OAuthDataProvider dataProvider) { + this.dataProvider = dataProvider; + } + + public void setClientProvider(ClientRegistrationProvider clientProvider) { + this.clientProvider = clientProvider; + } +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientTokens.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientTokens.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientTokens.java new file mode 100644 index 0000000..32c2859 --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/ClientTokens.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.cxf.rs.security.oauth2.common.Client; +import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken; +import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken; + +public class ClientTokens { + private Client client; + private List accessTokens = new LinkedList(); + private List refreshTokens = new LinkedList(); + public ClientTokens(Client c, + List accessTokens, + List refreshTokens) { + this.client = c; + this.accessTokens = accessTokens; + this.refreshTokens = refreshTokens; + } + public Client getClient() { + return client; + } + public List getAccessTokens() { + return accessTokens; + } + public List getRefreshTokens() { + return refreshTokens; + } +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/InvalidRegistration.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/InvalidRegistration.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/InvalidRegistration.java new file mode 100644 index 0000000..c0f54ee --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/InvalidRegistration.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +public class InvalidRegistration { + private String message; + public InvalidRegistration(String message) { + this.message = message; + } + public String getMessage() { + return message; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisterClient.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisterClient.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisterClient.java new file mode 100644 index 0000000..b1409f4 --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisterClient.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +import java.util.Map; + +public class RegisterClient { + private Map homeRealms; + public RegisterClient(Map homeRealms) { + this.homeRealms = homeRealms; + } + public Map getHomeRealms() { + return homeRealms; + } + + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisteredClients.java ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisteredClients.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisteredClients.java new file mode 100644 index 0000000..7fb35f3 --- /dev/null +++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/clients/RegisteredClients.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.cxf.fediz.service.oidc.clients; + +import java.util.Collection; + +import org.apache.cxf.rs.security.oauth2.common.Client; + +public class RegisteredClients { + private Collection clients; + public RegisteredClients(Collection clients) { + this.clients = clients; + } + public Collection getClients() { + return clients; + } + + +} http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/6e1c0ddf/services/oidc/src/main/webapp/WEB-INF/applicationContext.xml ---------------------------------------------------------------------- diff --git a/services/oidc/src/main/webapp/WEB-INF/applicationContext.xml b/services/oidc/src/main/webapp/WEB-INF/applicationContext.xml index 4ff8856..b676c98 100644 --- a/services/oidc/src/main/webapp/WEB-INF/applicationContext.xml +++ b/services/oidc/src/main/webapp/WEB-INF/applicationContext.xml @@ -117,7 +117,8 @@ - +