database storage for device flow
parent
04dd67d073
commit
44b24af466
|
@ -33,6 +33,8 @@ import javax.persistence.Id;
|
||||||
import javax.persistence.JoinColumn;
|
import javax.persistence.JoinColumn;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.MapKeyColumn;
|
import javax.persistence.MapKeyColumn;
|
||||||
|
import javax.persistence.NamedQueries;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
|
|
||||||
|
@ -42,8 +44,21 @@ import javax.persistence.Temporal;
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "device_code")
|
@Table(name = "device_code")
|
||||||
|
@NamedQueries({
|
||||||
|
@NamedQuery(name = DeviceCode.QUERY_BY_USER_CODE, query = "select d from DeviceCode d where d.userCode = :" + DeviceCode.PARAM_USER_CODE),
|
||||||
|
@NamedQuery(name = DeviceCode.QUERY_BY_DEVICE_CODE, query = "select d from DeviceCode d where d.deviceCode = :" + DeviceCode.PARAM_DEVICE_CODE),
|
||||||
|
@NamedQuery(name = DeviceCode.QUERY_EXPIRED_BY_DATE, query = "select d from DeviceCode d where d.expiration <= :" + DeviceCode.PARAM_DATE)
|
||||||
|
})
|
||||||
public class DeviceCode {
|
public class DeviceCode {
|
||||||
|
|
||||||
|
public static final String QUERY_BY_USER_CODE = "DeviceCode.queryByUserCode";
|
||||||
|
public static final String QUERY_BY_DEVICE_CODE = "DeviceCode.queryByDeviceCode";
|
||||||
|
public static final String QUERY_EXPIRED_BY_DATE = "DeviceCode.queryExpiredByDate";
|
||||||
|
|
||||||
|
public static final String PARAM_USER_CODE = "userCode";
|
||||||
|
public static final String PARAM_DEVICE_CODE = "deviceCode";
|
||||||
|
public static final String PARAM_DATE = "date";
|
||||||
|
|
||||||
private Long id;
|
private Long id;
|
||||||
private String deviceCode;
|
private String deviceCode;
|
||||||
private String userCode;
|
private String userCode;
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2017 The MITRE Corporation
|
||||||
|
* and 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.repository.impl;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mitre.oauth2.model.DeviceCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface DeviceCodeRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DeviceCode getById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param deviceCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DeviceCode getByDeviceCode(String deviceCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param scope
|
||||||
|
*/
|
||||||
|
public void remove(DeviceCode scope);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param scope
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DeviceCode save(DeviceCode scope);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param userCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DeviceCode getByUserCode(String userCode);
|
||||||
|
|
||||||
|
}
|
|
@ -131,7 +131,7 @@ CREATE TABLE IF NOT EXISTS client_details (
|
||||||
dynamically_registered BOOLEAN DEFAULT false NOT NULL,
|
dynamically_registered BOOLEAN DEFAULT false NOT NULL,
|
||||||
allow_introspection BOOLEAN DEFAULT false NOT NULL,
|
allow_introspection BOOLEAN DEFAULT false NOT NULL,
|
||||||
id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL,
|
id_token_validity_seconds BIGINT DEFAULT 600 NOT NULL,
|
||||||
device_code_validity_seconds BIGINT DEFAULT 600 NOT NULL,
|
device_code_validity_seconds BIGINT,
|
||||||
|
|
||||||
client_id VARCHAR(256),
|
client_id VARCHAR(256),
|
||||||
client_secret VARCHAR(2048),
|
client_secret VARCHAR(2048),
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2017 The MITRE Corporation
|
||||||
|
* and 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.repository.impl;
|
||||||
|
|
||||||
|
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
|
||||||
|
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.PersistenceContext;
|
||||||
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
|
import org.mitre.oauth2.model.DeviceCode;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Repository("jpaDeviceCodeRepository")
|
||||||
|
public class JpaDeviceCodeRepository implements DeviceCodeRepository {
|
||||||
|
|
||||||
|
@PersistenceContext(unitName="defaultPersistenceUnit")
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(value="defaultTransactionManager")
|
||||||
|
public DeviceCode getById(Long id) {
|
||||||
|
return em.find(DeviceCode.class, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(value="defaultTransactionManager")
|
||||||
|
public DeviceCode getByUserCode(String value) {
|
||||||
|
TypedQuery<DeviceCode> query = em.createNamedQuery(DeviceCode.QUERY_BY_USER_CODE, DeviceCode.class);
|
||||||
|
query.setParameter(DeviceCode.PARAM_USER_CODE, value);
|
||||||
|
return getSingleResult(query.getResultList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(value="defaultTransactionManager")
|
||||||
|
public DeviceCode getByDeviceCode(String value) {
|
||||||
|
TypedQuery<DeviceCode> query = em.createNamedQuery(DeviceCode.QUERY_BY_DEVICE_CODE, DeviceCode.class);
|
||||||
|
query.setParameter(DeviceCode.PARAM_DEVICE_CODE, value);
|
||||||
|
return getSingleResult(query.getResultList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(value="defaultTransactionManager")
|
||||||
|
public void remove(DeviceCode scope) {
|
||||||
|
DeviceCode found = getById(scope.getId());
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
em.remove(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.mitre.oauth2.repository.SystemScopeRepository#save(org.mitre.oauth2.model.SystemScope)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(value="defaultTransactionManager")
|
||||||
|
public DeviceCode save(DeviceCode scope) {
|
||||||
|
return saveOrUpdate(scope.getId(), em, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,15 +18,15 @@
|
||||||
package org.mitre.oauth2.service.impl;
|
package org.mitre.oauth2.service.impl;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
import org.mitre.oauth2.model.DeviceCode;
|
import org.mitre.oauth2.model.DeviceCode;
|
||||||
|
import org.mitre.oauth2.repository.impl.DeviceCodeRepository;
|
||||||
import org.mitre.oauth2.service.DeviceCodeService;
|
import org.mitre.oauth2.service.DeviceCodeService;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -35,10 +35,11 @@ import org.springframework.stereotype.Service;
|
||||||
* @author jricher
|
* @author jricher
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service("defaultDeviceCodeService")
|
||||||
public class InMemoryDeviceCodeService implements DeviceCodeService {
|
public class DefaultDeviceCodeService implements DeviceCodeService {
|
||||||
|
|
||||||
private Set<DeviceCode> codes = new HashSet<>();
|
@Autowired
|
||||||
|
private DeviceCodeRepository repository;
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.mitre.oauth2.service.DeviceCodeService#save(org.mitre.oauth2.model.DeviceCode)
|
* @see org.mitre.oauth2.service.DeviceCodeService#save(org.mitre.oauth2.model.DeviceCode)
|
||||||
|
@ -54,8 +55,7 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
||||||
|
|
||||||
dc.setApproved(false);
|
dc.setApproved(false);
|
||||||
|
|
||||||
codes.add(dc);
|
return repository.save(dc);
|
||||||
return dc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -63,12 +63,7 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeviceCode lookUpByUserCode(String userCode) {
|
public DeviceCode lookUpByUserCode(String userCode) {
|
||||||
for (DeviceCode dc : codes) {
|
return repository.getByUserCode(userCode);
|
||||||
if (dc.getUserCode().equals(userCode)) {
|
|
||||||
return dc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -76,13 +71,16 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeviceCode approveDeviceCode(DeviceCode dc, OAuth2Authentication auth) {
|
public DeviceCode approveDeviceCode(DeviceCode dc, OAuth2Authentication auth) {
|
||||||
dc.setApproved(true);
|
DeviceCode found = repository.getById(dc.getId());
|
||||||
|
|
||||||
|
found.setApproved(true);
|
||||||
|
|
||||||
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
||||||
authHolder.setAuthentication(auth);
|
authHolder.setAuthentication(auth);
|
||||||
dc.setAuthenticationHolder(authHolder);
|
|
||||||
|
|
||||||
return dc;
|
found.setAuthenticationHolder(authHolder);
|
||||||
|
|
||||||
|
return repository.save(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -90,13 +88,19 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeviceCode consumeDeviceCode(String deviceCode, ClientDetails client) {
|
public DeviceCode consumeDeviceCode(String deviceCode, ClientDetails client) {
|
||||||
for (DeviceCode dc : codes) {
|
DeviceCode found = repository.getByDeviceCode(deviceCode);
|
||||||
if (dc.getDeviceCode().equals(deviceCode) && dc.getClientId().equals(client.getClientId())) {
|
|
||||||
codes.remove(dc);
|
// make sure it's not used twice
|
||||||
return dc;
|
repository.remove(found);
|
||||||
}
|
|
||||||
|
if (found.getClientId().equals(client.getClientId())) {
|
||||||
|
// make sure the client matches, if so, we're good
|
||||||
|
return found;
|
||||||
|
} else {
|
||||||
|
// if the clients don't match, pretend the code wasn't found
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ package org.mitre.oauth2.web;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -147,12 +148,15 @@ public class DeviceEndpoint {
|
||||||
|
|
||||||
DeviceCode dc = deviceCodeService.createNewDeviceCode(deviceCode, userCode, requestedScopes, client, parameters);
|
DeviceCode dc = deviceCodeService.createNewDeviceCode(deviceCode, userCode, requestedScopes, client, parameters);
|
||||||
|
|
||||||
model.put(JsonEntityView.ENTITY, ImmutableMap.of(
|
Map<String, Object> response = new HashMap<>();
|
||||||
"device_code", deviceCode,
|
response.put("device_code", deviceCode);
|
||||||
"user_code", userCode,
|
response.put("user_code", userCode);
|
||||||
"verification_uri", config.getIssuer() + URL,
|
response.put("verification_uri", config.getIssuer() + USER_URL);
|
||||||
"expires_in", client.getDeviceCodeValiditySeconds()
|
if (client.getDeviceCodeValiditySeconds() != null) {
|
||||||
));
|
response.put("expires_in", client.getDeviceCodeValiditySeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
model.put(JsonEntityView.ENTITY, response);
|
||||||
|
|
||||||
|
|
||||||
return JsonEntityView.VIEWNAME;
|
return JsonEntityView.VIEWNAME;
|
||||||
|
|
Loading…
Reference in New Issue