database storage for device flow
parent
04dd67d073
commit
44b24af466
|
@ -33,6 +33,8 @@ import javax.persistence.Id;
|
|||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
|
||||
|
@ -42,8 +44,21 @@ import javax.persistence.Temporal;
|
|||
*/
|
||||
@Entity
|
||||
@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 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 String deviceCode;
|
||||
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,
|
||||
allow_introspection BOOLEAN DEFAULT false 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_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;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.model.AuthenticationHolderEntity;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.DeviceCode;
|
||||
import org.mitre.oauth2.repository.impl.DeviceCodeRepository;
|
||||
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.OAuth2Authentication;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -35,10 +35,11 @@ import org.springframework.stereotype.Service;
|
|||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class InMemoryDeviceCodeService implements DeviceCodeService {
|
||||
@Service("defaultDeviceCodeService")
|
||||
public class DefaultDeviceCodeService implements DeviceCodeService {
|
||||
|
||||
private Set<DeviceCode> codes = new HashSet<>();
|
||||
@Autowired
|
||||
private DeviceCodeRepository repository;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.DeviceCodeService#save(org.mitre.oauth2.model.DeviceCode)
|
||||
|
@ -54,8 +55,7 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
|||
|
||||
dc.setApproved(false);
|
||||
|
||||
codes.add(dc);
|
||||
return dc;
|
||||
return repository.save(dc);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -63,12 +63,7 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
|||
*/
|
||||
@Override
|
||||
public DeviceCode lookUpByUserCode(String userCode) {
|
||||
for (DeviceCode dc : codes) {
|
||||
if (dc.getUserCode().equals(userCode)) {
|
||||
return dc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return repository.getByUserCode(userCode);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -76,13 +71,16 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
|||
*/
|
||||
@Override
|
||||
public DeviceCode approveDeviceCode(DeviceCode dc, OAuth2Authentication auth) {
|
||||
dc.setApproved(true);
|
||||
DeviceCode found = repository.getById(dc.getId());
|
||||
|
||||
found.setApproved(true);
|
||||
|
||||
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
|
||||
authHolder.setAuthentication(auth);
|
||||
dc.setAuthenticationHolder(authHolder);
|
||||
|
||||
return dc;
|
||||
found.setAuthenticationHolder(authHolder);
|
||||
|
||||
return repository.save(found);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -90,13 +88,19 @@ public class InMemoryDeviceCodeService implements DeviceCodeService {
|
|||
*/
|
||||
@Override
|
||||
public DeviceCode consumeDeviceCode(String deviceCode, ClientDetails client) {
|
||||
for (DeviceCode dc : codes) {
|
||||
if (dc.getDeviceCode().equals(deviceCode) && dc.getClientId().equals(client.getClientId())) {
|
||||
codes.remove(dc);
|
||||
return dc;
|
||||
}
|
||||
DeviceCode found = repository.getByDeviceCode(deviceCode);
|
||||
|
||||
// make sure it's not used twice
|
||||
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.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -147,12 +148,15 @@ public class DeviceEndpoint {
|
|||
|
||||
DeviceCode dc = deviceCodeService.createNewDeviceCode(deviceCode, userCode, requestedScopes, client, parameters);
|
||||
|
||||
model.put(JsonEntityView.ENTITY, ImmutableMap.of(
|
||||
"device_code", deviceCode,
|
||||
"user_code", userCode,
|
||||
"verification_uri", config.getIssuer() + URL,
|
||||
"expires_in", client.getDeviceCodeValiditySeconds()
|
||||
));
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("device_code", deviceCode);
|
||||
response.put("user_code", userCode);
|
||||
response.put("verification_uri", config.getIssuer() + USER_URL);
|
||||
if (client.getDeviceCodeValiditySeconds() != null) {
|
||||
response.put("expires_in", client.getDeviceCodeValiditySeconds());
|
||||
}
|
||||
|
||||
model.put(JsonEntityView.ENTITY, response);
|
||||
|
||||
|
||||
return JsonEntityView.VIEWNAME;
|
||||
|
|
Loading…
Reference in New Issue