Improving the current dynamic client authentication to be more spec compliant

4.x.x
prabathabey 10 years ago
parent 6b459afd84
commit 2dc1c7341a

@ -18,8 +18,12 @@
*/ */
package org.wso2.carbon.identity.oauth.extension; package org.wso2.carbon.identity.oauth.extension;
public class ApplicationConstants { public final class ApplicationConstants {
public static class ClientMetadata {
private ClientMetadata() {
throw new AssertionError();
}
public static final String OAUTH_CLIENT_ID = "client_id"; //this means consumer key public static final String OAUTH_CLIENT_ID = "client_id"; //this means consumer key
public static final String OAUTH_CLIENT_SECRET = "client_secret"; public static final String OAUTH_CLIENT_SECRET = "client_secret";
public static final String OAUTH_REDIRECT_URIS = "redirect_uris"; public static final String OAUTH_REDIRECT_URIS = "redirect_uris";
@ -46,5 +50,6 @@ public class ApplicationConstants {
public static final String OAUTH_CLIENT_USERNAME = "username"; public static final String OAUTH_CLIENT_USERNAME = "username";
public static final String OAUTH_CLIENT_APPLICATION = "application"; public static final String OAUTH_CLIENT_APPLICATION = "application";
public static final String VALIDITY_PERIOD = "validityPeriod"; public static final String VALIDITY_PERIOD = "validityPeriod";
}
} }

@ -0,0 +1,77 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.identity.oauth.extension;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
@Provider
@Produces(MediaType.APPLICATION_JSON)
public class FaultMessageBodyWriter implements MessageBodyWriter<FaultResponse> {
private static final String UTF_8 = "UTF-8";
@Override
public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
return (FaultResponse.class == type);
}
@Override
public long getSize(FaultResponse faultResponse, Class<?> aClass, Type type, Annotation[] annotations,
MediaType mediaType) {
return -1;
}
@Override
public void writeTo(FaultResponse faultResponse, Class<?> aClass, Type type, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> stringObjectMultivaluedMap,
OutputStream outputStream) throws IOException, WebApplicationException {
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(outputStream, UTF_8);
JsonObject response = new JsonObject();
response.addProperty("error", faultResponse.getCode().getValue());
response.addProperty("error_description", faultResponse.getDescription());
getGson().toJson(response, type, writer);
} finally {
if (writer != null) {
writer.close();
}
}
}
private Gson getGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
return gsonBuilder.create();
}
}

@ -0,0 +1,39 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.identity.oauth.extension;
public class FaultResponse {
private RegistrationService.ErrorCode code;
private String description;
public FaultResponse(RegistrationService.ErrorCode code, String description) {
this.code = code;
this.description = description;
}
public RegistrationService.ErrorCode getCode() {
return code;
}
public String getDescription() {
return description;
}
}

@ -27,24 +27,16 @@ import java.util.Map;
public class OAuthApplicationInfo { public class OAuthApplicationInfo {
private String clientId; private String clientId;
private String clientName; private String clientName;
private String callBackURL; private String callBackURL;
private String clientSecret; private String clientSecret;
private Map<String,Object> parameters = new HashMap<String, Object>(); private Map<String,Object> parameters = new HashMap<String, Object>();
/**
* get client Id (consumer id)
* @return clientId
*/
public String getClientId() { public String getClientId() {
return clientId; return clientId;
} }
/**
* set client Id
* @param clientId
*/
public void setClientId(String clientId) { public void setClientId(String clientId) {
this.clientId = clientId; this.clientId = clientId;
} }
@ -57,18 +49,10 @@ public class OAuthApplicationInfo {
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
} }
/**
* Set client Name of OAuthApplication.
* @param clientName
*/
public void setClientName(String clientName){ public void setClientName(String clientName){
this.clientName = clientName; this.clientName = clientName;
} }
/**
* Set callback URL of OAuthapplication.
* @param callBackURL
*/
public void setCallBackURL(String callBackURL){ public void setCallBackURL(String callBackURL){
this.callBackURL = callBackURL; this.callBackURL = callBackURL;
} }
@ -82,9 +66,7 @@ public class OAuthApplicationInfo {
} }
public String getJsonString(){ public String getJsonString(){
return JSONObject.toJSONString(parameters); return JSONObject.toJSONString(parameters);
} }
public String getClientName(){ public String getClientName(){

@ -18,6 +18,9 @@
*/ */
package org.wso2.carbon.identity.oauth.extension; package org.wso2.carbon.identity.oauth.extension;
import org.wso2.carbon.identity.oauth.extension.profile.RegistrationProfile;
import org.wso2.carbon.identity.oauth.extension.profile.UnregistrationProfile;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.POST; import javax.ws.rs.POST;
@ -29,6 +32,19 @@ import javax.ws.rs.core.Response;
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public interface RegistrationService { public interface RegistrationService {
enum ErrorCode {
INVALID_URI("invalid_redirect_uri"), INVALID_CLIENT_METADATA("invalid_client_metadata");
private String value;
private ErrorCode(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
@POST @POST
Response register(RegistrationProfile profile); Response register(RegistrationProfile profile);

@ -0,0 +1,33 @@
/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.identity.oauth.extension.impl;
import org.wso2.carbon.identity.oauth.extension.ConfigurationService;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
public class ConfigurationServiceImpl implements ConfigurationService {
@Override
public Response getProfile(@PathParam("client_id") String clientId) {
return null;
}
}

@ -35,11 +35,9 @@ import org.wso2.carbon.identity.application.mgt.ApplicationManagementService;
import org.wso2.carbon.identity.base.IdentityException; import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.oauth.OAuthAdminService; import org.wso2.carbon.identity.oauth.OAuthAdminService;
import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO; import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO;
import org.wso2.carbon.identity.oauth.extension.ApplicationConstants; import org.wso2.carbon.identity.oauth.extension.*;
import org.wso2.carbon.identity.oauth.extension.OAuthApplicationInfo; import org.wso2.carbon.identity.oauth.extension.profile.RegistrationProfile;
import org.wso2.carbon.identity.oauth.extension.RegistrationProfile; import org.wso2.carbon.identity.oauth.extension.profile.UnregistrationProfile;
import org.wso2.carbon.identity.oauth.extension.RegistrationService;
import org.wso2.carbon.identity.oauth.extension.UnregistrationProfile;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
@ -53,9 +51,9 @@ import java.util.Arrays;
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public class ClientRegistrationServiceImpl implements RegistrationService { public class RegistrationServiceImpl implements RegistrationService {
private static final Log log = LogFactory.getLog(ClientRegistrationServiceImpl.class); private static final Log log = LogFactory.getLog(RegistrationServiceImpl.class);
@POST @POST
@Override @Override
@ -71,7 +69,7 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
} catch (APIManagementException e) { } catch (APIManagementException e) {
String msg = "Error occurred while registering client '" + profile.getClientName() + "'"; String msg = "Error occurred while registering client '" + profile.getClientName() + "'";
log.error(msg, e); log.error(msg, e);
return Response.serverError().entity(msg).build(); return Response.serverError().entity(new FaultResponse(ErrorCode.INVALID_CLIENT_METADATA, msg)).build();
} finally { } finally {
PrivilegedCarbonContext.endTenantFlow(); PrivilegedCarbonContext.endTenantFlow();
} }
@ -87,13 +85,12 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
this.unregisterApplication(userId, applicationName, consumerKey); this.unregisterApplication(userId, applicationName, consumerKey);
return Response.status(Response.Status.ACCEPTED).build(); return Response.status(Response.Status.ACCEPTED).build();
} catch (APIManagementException e) { } catch (APIManagementException e) {
String msg = "Error occurred while unregistering client '" + applicationName + "'"; String msg = "Error occurred while un-registering client '" + applicationName + "'";
log.error(msg, e); log.error(msg, e);
return Response.serverError().entity(msg).build(); return Response.serverError().entity(new FaultResponse(ErrorCode.INVALID_CLIENT_METADATA, msg)).build();
} }
} }
private OAuthApplicationInfo registerApplication(RegistrationProfile profile) throws APIManagementException { private OAuthApplicationInfo registerApplication(RegistrationProfile profile) throws APIManagementException {
OAuthApplicationInfo oAuthApplicationInfo = new OAuthApplicationInfo(); OAuthApplicationInfo oAuthApplicationInfo = new OAuthApplicationInfo();
@ -131,16 +128,15 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
try { try {
JSONObject jsonObject = new JSONObject(info.getJsonString()); JSONObject jsonObject = new JSONObject(info.getJsonString());
if (jsonObject.has(ApplicationConstants.OAUTH_REDIRECT_URIS)) { if (jsonObject.has(ApplicationConstants.ClientMetadata.OAUTH_REDIRECT_URIS)) {
oAuthApplicationInfo.addParameter(ApplicationConstants.OAUTH_REDIRECT_URIS, jsonObject.get(ApplicationConstants.OAUTH_REDIRECT_URIS)); oAuthApplicationInfo.addParameter(ApplicationConstants.ClientMetadata.OAUTH_REDIRECT_URIS,
jsonObject.get(ApplicationConstants.ClientMetadata.OAUTH_REDIRECT_URIS));
} }
if (jsonObject.has(ApplicationConstants.OAUTH_CLIENT_GRANT)) { if (jsonObject.has(ApplicationConstants.ClientMetadata.OAUTH_CLIENT_GRANT)) {
oAuthApplicationInfo.addParameter(ApplicationConstants. oAuthApplicationInfo.addParameter(ApplicationConstants.ClientMetadata.
OAUTH_CLIENT_GRANT, jsonObject.get(ApplicationConstants.OAUTH_CLIENT_GRANT)); OAUTH_CLIENT_GRANT, jsonObject.get(ApplicationConstants.ClientMetadata.OAUTH_CLIENT_GRANT));
} }
} catch (JSONException e) { } catch (JSONException e) {
throw new APIManagementException("Can not retrieve information of the created OAuth application", e); throw new APIManagementException("Can not retrieve information of the created OAuth application", e);
} }
@ -167,7 +163,6 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(userName); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(userName);
try { try {
// Append the username before Application name to make application name unique across two users. // Append the username before Application name to make application name unique across two users.
applicationName = userName + "_" + applicationName; applicationName = userName + "_" + applicationName;
@ -180,7 +175,6 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
appMgtService.createApplication(serviceProvider); appMgtService.createApplication(serviceProvider);
ServiceProvider createdServiceProvider = appMgtService.getApplication(applicationName); ServiceProvider createdServiceProvider = appMgtService.getApplication(applicationName);
if (createdServiceProvider == null) { if (createdServiceProvider == null) {
throw new APIManagementException("Couldn't create Service Provider Application " + applicationName); throw new APIManagementException("Couldn't create Service Provider Application " + applicationName);
} }
@ -189,17 +183,23 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
OAuthAdminService oAuthAdminService = new OAuthAdminService(); OAuthAdminService oAuthAdminService = new OAuthAdminService();
OAuthConsumerAppDTO oAuthConsumerAppDTO = new OAuthConsumerAppDTO(); OAuthConsumerAppDTO oAuthConsumerAppDTO = new OAuthConsumerAppDTO();
oAuthConsumerAppDTO.setApplicationName(applicationName); oAuthConsumerAppDTO.setApplicationName(applicationName);
oAuthConsumerAppDTO.setCallbackUrl(callbackUrl); oAuthConsumerAppDTO.setCallbackUrl(callbackUrl);
oAuthConsumerAppDTO.setGrantTypes(grantType); oAuthConsumerAppDTO.setGrantTypes(grantType);
if (log.isDebugEnabled()) {
log.debug("Creating OAuth App " + applicationName); log.debug("Creating OAuth App " + applicationName);
}
oAuthAdminService.registerOAuthApplicationData(oAuthConsumerAppDTO); oAuthAdminService.registerOAuthApplicationData(oAuthConsumerAppDTO);
if (log.isDebugEnabled()) {
log.debug("Created OAuth App " + applicationName); log.debug("Created OAuth App " + applicationName);
}
OAuthConsumerAppDTO createdApp = oAuthAdminService.getOAuthApplicationDataByAppName(oAuthConsumerAppDTO OAuthConsumerAppDTO createdApp = oAuthAdminService.getOAuthApplicationDataByAppName(oAuthConsumerAppDTO
.getApplicationName()); .getApplicationName());
if (log.isDebugEnabled()) {
log.debug("Retrieved Details for OAuth App " + createdApp.getApplicationName()); log.debug("Retrieved Details for OAuth App " + createdApp.getApplicationName());
}
// Set the OAuthApp in InboundAuthenticationConfig // Set the OAuthApp in InboundAuthenticationConfig
InboundAuthenticationConfig inboundAuthenticationConfig = new InboundAuthenticationConfig(); InboundAuthenticationConfig inboundAuthenticationConfig = new InboundAuthenticationConfig();
InboundAuthenticationRequestConfig[] inboundAuthenticationRequestConfigs = new InboundAuthenticationRequestConfig[] inboundAuthenticationRequestConfigs = new
@ -225,20 +225,17 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
// Update the Service Provider app to add OAuthApp as an Inbound Authentication Config // Update the Service Provider app to add OAuthApp as an Inbound Authentication Config
appMgtService.updateApplication(createdServiceProvider); appMgtService.updateApplication(createdServiceProvider);
OAuthApplicationInfo oAuthApplicationInfo = new OAuthApplicationInfo(); OAuthApplicationInfo oAuthApplicationInfo = new OAuthApplicationInfo();
oAuthApplicationInfo.setClientId(createdApp.getOauthConsumerKey()); oAuthApplicationInfo.setClientId(createdApp.getOauthConsumerKey());
oAuthApplicationInfo.setCallBackURL(createdApp.getCallbackUrl()); oAuthApplicationInfo.setCallBackURL(createdApp.getCallbackUrl());
oAuthApplicationInfo.setClientSecret(createdApp.getOauthConsumerSecret()); oAuthApplicationInfo.setClientSecret(createdApp.getOauthConsumerSecret());
oAuthApplicationInfo.setClientName(createdApp.getApplicationName()); oAuthApplicationInfo.setClientName(createdApp.getApplicationName());
oAuthApplicationInfo.addParameter(ApplicationConstants. oAuthApplicationInfo.addParameter(
OAUTH_REDIRECT_URIS, createdApp.getCallbackUrl()); ApplicationConstants.ClientMetadata.OAUTH_REDIRECT_URIS, createdApp.getCallbackUrl());
oAuthApplicationInfo.addParameter(ApplicationConstants. oAuthApplicationInfo.addParameter(
OAUTH_CLIENT_GRANT, createdApp.getGrantTypes()); ApplicationConstants.ClientMetadata.OAUTH_CLIENT_GRANT, createdApp.getGrantTypes());
return oAuthApplicationInfo; return oAuthApplicationInfo;
} catch (IdentityApplicationManagementException e) { } catch (IdentityApplicationManagementException e) {
APIUtil.handleException("Error occurred while creating ServiceProvider for app " + applicationName, e); APIUtil.handleException("Error occurred while creating ServiceProvider for app " + applicationName, e);
} catch (Exception e) { } catch (Exception e) {
@ -250,9 +247,8 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
return null; return null;
} }
public void unregisterApplication(String userId, String applicationName, String consumerKey) public void unregisterApplication(String userId, String applicationName,
throws APIManagementException { String consumerKey) throws APIManagementException {
String tenantDomain = MultitenantUtils.getTenantDomain(userId); String tenantDomain = MultitenantUtils.getTenantDomain(userId);
String baseUser = CarbonContext.getThreadLocalCarbonContext().getUsername(); String baseUser = CarbonContext.getThreadLocalCarbonContext().getUsername();
String userName = MultitenantUtils.getTenantAwareUsername(userId); String userName = MultitenantUtils.getTenantAwareUsername(userId);
@ -262,7 +258,8 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(userName); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(userName);
if (userId == null || userId.isEmpty()) { if (userId == null || userId.isEmpty()) {
throw new APIManagementException("Error occurred while unregistering Application: userId cannot be null/empty"); throw new APIManagementException("Error occurred while unregistering Application: userId cannot " +
"be null/empty");
} }
try { try {
OAuthAdminService oAuthAdminService = new OAuthAdminService(); OAuthAdminService oAuthAdminService = new OAuthAdminService();
@ -291,4 +288,5 @@ public class ClientRegistrationServiceImpl implements RegistrationService {
PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(baseUser); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(baseUser);
} }
} }
} }

@ -16,7 +16,7 @@
* under the License. * under the License.
* *
*/ */
package org.wso2.carbon.identity.oauth.extension; package org.wso2.carbon.identity.oauth.extension.profile;
public class RegistrationProfile { public class RegistrationProfile {

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.wso2.carbon.identity.oauth.extension; package org.wso2.carbon.identity.oauth.extension.profile;
/** /**
* This bean class represents the data that are required to unregister * This bean class represents the data that are required to unregister

@ -33,10 +33,12 @@
</jaxrs:serviceBeans> </jaxrs:serviceBeans>
<jaxrs:providers> <jaxrs:providers>
<ref bean="jsonProvider"/> <ref bean="jsonProvider"/>
<ref bean="faultResponseWriter"/>
</jaxrs:providers> </jaxrs:providers>
</jaxrs:server> </jaxrs:server>
<bean id="RegistrationServiceBean" class="org.wso2.carbon.identity.oauth.extension.impl.ClientRegistrationServiceImpl"/> <bean id="RegistrationServiceBean" class="org.wso2.carbon.identity.oauth.extension.impl.RegistrationServiceImpl"/>
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/> <bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
<bean id="faultResponseWriter" class="org.wso2.carbon.identity.oauth.extension.FaultMessageBodyWriter"/>
</beans> </beans>

Loading…
Cancel
Save