diff --git a/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java b/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java index c161c0797..e13fe7c4a 100644 --- a/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java +++ b/openid-connect-common/src/main/java/org/mitre/oauth2/model/ClientDetailsEntity.java @@ -148,6 +148,7 @@ public class ClientDetailsEntity implements ClientDetails { private Date createdAt; // time the client was created private boolean clearAccessTokensOnRefresh = true; // do we clear access tokens on refresh? private Integer deviceCodeValiditySeconds; // timeout for device codes + private boolean verificationUriCompleteEnabled = true; // device code optional feature /** fields for UMA */ private Set claimsRedirectUris; @@ -1051,6 +1052,22 @@ public class ClientDetailsEntity implements ClientDetails { this.deviceCodeValiditySeconds = deviceCodeValiditySeconds; } + /** + * @return true if verification uri complete in device code flow is enabled, false otherwise + */ + @Basic + @Column(name="verification_uri_complete_enabled") + public boolean isVerificationUriCompleteEnabled() { + return verificationUriCompleteEnabled; + } + + /** + * @param verificationUriCompleteEnabled true/false to enable/disable verification uri complete functionality in device code flow + */ + public void setVerificationUriCompleteEnabled(boolean verificationUriCompleteEnabled) { + this.verificationUriCompleteEnabled = verificationUriCompleteEnabled; + } + /** * @return the softwareId */ diff --git a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql index 2a0175629..0152edc88 100644 --- a/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql +++ b/openid-connect-server-webapp/src/main/resources/db/hsql/hsql_database_tables.sql @@ -132,6 +132,7 @@ CREATE TABLE IF NOT EXISTS client_details ( allow_introspection BOOLEAN DEFAULT false NOT NULL, id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, device_code_validity_seconds BIGINT, + verification_uri_complete_enabled BOOLEAN DEFAULT true NOT NULL, client_id VARCHAR(256), client_secret VARCHAR(2048), diff --git a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql index 7e00cc876..c1fb52564 100644 --- a/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql +++ b/openid-connect-server-webapp/src/main/resources/db/mysql/mysql_database_tables.sql @@ -131,6 +131,7 @@ CREATE TABLE IF NOT EXISTS client_details ( allow_introspection BOOLEAN DEFAULT false NOT NULL, id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, device_code_validity_seconds BIGINT, + verification_uri_complete_enabled BOOLEAN DEFAULT true NOT NULL, client_id VARCHAR(256), client_secret VARCHAR(2048), diff --git a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql index 5f88b689b..757d4434e 100644 --- a/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql +++ b/openid-connect-server-webapp/src/main/resources/db/oracle/oracle_database_tables.sql @@ -147,6 +147,7 @@ CREATE TABLE client_details ( access_token_validity_seconds NUMBER(19), refresh_token_validity_seconds NUMBER(19), device_code_validity_seconds NUMBER(19), + verification_uri_complete_enabled NUMBER(1) DEFAULT 1 NOT NULL, application_type VARCHAR2(256), client_name VARCHAR2(256), diff --git a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql index a9992993f..dc2ba673d 100644 --- a/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql +++ b/openid-connect-server-webapp/src/main/resources/db/psql/psql_database_tables.sql @@ -132,6 +132,7 @@ CREATE TABLE IF NOT EXISTS client_details ( allow_introspection BOOLEAN DEFAULT false NOT NULL, id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL, device_code_validity_seconds BIGINT, + verification_uri_complete_enabled BOOLEAN DEFAULT true NOT NULL, client_id VARCHAR(256), client_secret VARCHAR(2048), diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json b/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json index c513e62c6..b142f0a9b 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/locale/en/messages.json @@ -510,7 +510,7 @@ "expiredUserCode": "The code that you entered has expired. Return to your device and request a new code.", "userCodeAlreadyApproved": "The code that you entered has already been used.", "userCodeMismatch": "There was an error processing the code you entered. Try refreshing the page and returning to your device to request a new code.", - "error": "There was an error processing the code you entered. Return to your device adn request a new code." + "error": "There was an error processing the code you entered. Return to your device and request a new code." }, "approve": { "approved": "The device has been approved.", diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/exception/CompleteVerificationUriDisabledException.java b/openid-connect-server/src/main/java/org/mitre/oauth2/exception/CompleteVerificationUriDisabledException.java new file mode 100644 index 000000000..ee9f7ed8f --- /dev/null +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/exception/CompleteVerificationUriDisabledException.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright 2018 The MIT Internet Trust Consortium + * + * 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.mitre.oauth2.exception; + +/** + * @author ondrejvelisek + * + */ +public class CompleteVerificationUriDisabledException extends RuntimeException { + + /** + * @param clientId of client + */ + public CompleteVerificationUriDisabledException(String clientId) { + super("complete verification uri was attempted to be used but such functionality is not enabled for client " + clientId); + } + + private static final long serialVersionUID = -7078098692596870940L; + +} diff --git a/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java b/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java index 9e2bac67f..97b5ad275 100644 --- a/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/oauth2/web/DeviceEndpoint.java @@ -24,11 +24,11 @@ import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; -import java.util.UUID; import javax.servlet.http.HttpSession; import org.apache.http.client.utils.URIBuilder; +import org.mitre.oauth2.exception.CompleteVerificationUriDisabledException; import org.mitre.oauth2.exception.DeviceCodeCreationException; import org.mitre.oauth2.model.ClientDetailsEntity; import org.mitre.oauth2.model.DeviceCode; @@ -50,7 +50,6 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.oauth2.common.exceptions.InvalidClientException; import org.springframework.security.oauth2.common.util.OAuth2Utils; -import org.springframework.security.oauth2.common.util.RandomValueStringGenerator; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; @@ -138,15 +137,16 @@ public class DeviceEndpoint { try { DeviceCode dc = deviceCodeService.createNewDeviceCode(requestedScopes, client, parameters); - URI verificationUriComplete = new URIBuilder(config.getIssuer() + USER_URL) - .addParameter("user_code", dc.getUserCode()) - .build(); - Map response = new HashMap<>(); response.put("device_code", dc.getDeviceCode()); response.put("user_code", dc.getUserCode()); response.put("verification_uri", config.getIssuer() + USER_URL); - response.put("verification_uri_complete", verificationUriComplete); + if (client.isVerificationUriCompleteEnabled()) { + URI verificationUriComplete = new URIBuilder(config.getIssuer() + USER_URL) + .addParameter("user_code", dc.getUserCode()) + .build(); + response.put("verification_uri_complete", verificationUriComplete); + } if (client.getDeviceCodeValiditySeconds() != null) { response.put("expires_in", client.getDeviceCodeValiditySeconds()); } @@ -185,6 +185,7 @@ public class DeviceEndpoint { // complete verification uri was used, we received user code directly // skip requesting code page // user must be logged in + model.addAttribute("completeVerificationUriUsed", true); return readUserCode(userCode, model, session); } } @@ -216,6 +217,10 @@ public class DeviceEndpoint { ClientDetailsEntity client = clientService.loadClientByClientId(dc.getClientId()); + if (!client.isVerificationUriCompleteEnabled() && Boolean.TRUE.equals(model.get("completeVerificationUriUsed"))) { + throw new CompleteVerificationUriDisabledException(client.getClientId()); + } + model.put("client", client); model.put("dc", dc);