refactor: 💡 Removed PerunACR and PerunDeviceACR

Removed models and repositories, removed scheduled tasks tied to these
classes. Acr is now instead stored together with the User authentication
pull/1580/head
Dominik Frantisek Bucik 2021-11-23 18:12:05 +01:00
parent 7155e4adf5
commit f85cd5c1c5
No known key found for this signature in database
GPG Key ID: 25014C8DB2E7E62D
7 changed files with 1 additions and 524 deletions

View File

@ -4,8 +4,6 @@ import cz.muni.ics.oauth2.model.AuthorizationCodeEntity;
import cz.muni.ics.oauth2.model.DeviceCode;
import cz.muni.ics.oauth2.model.OAuth2AccessTokenEntity;
import cz.muni.ics.oauth2.model.OAuth2RefreshTokenEntity;
import cz.muni.ics.openid.connect.models.Acr;
import cz.muni.ics.openid.connect.models.DeviceCodeAcr;
import java.time.Instant;
import java.util.Date;
import javax.persistence.EntityManager;
@ -135,38 +133,4 @@ public class CustomClearTasks {
return count;
}
public int clearExpiredAcrs(long timeout) {
manager.flush();
manager.clear();
int count = 0;
Query query = manager.createNamedQuery(Acr.DELETE_EXPIRED);
query.setParameter(Acr.PARAM_EXPIRES_AT, Instant.now().toEpochMilli());
if (timeout > 0) {
query.setHint("javax.persistence.query.timeout", timeout);
}
try {
count += query.executeUpdate();
} catch (QueryTimeoutException e) {
// this is OK
}
return count;
}
public int clearExpiredDeviceCodeAcrs(long timeout) {
manager.flush();
manager.clear();
int count = 0;
Query query = manager.createNamedQuery(DeviceCodeAcr.DELETE_EXPIRED);
query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, Instant.now().toEpochMilli());
if (timeout > 0) {
query.setHint("javax.persistence.query.timeout", timeout);
}
try {
count += query.executeUpdate();
} catch (QueryTimeoutException e) {
// this is OK
}
return count;
}
}

View File

@ -105,34 +105,4 @@ public class CustomTaskScheduler {
log.info("clearExpiredDeviceCodes took {}ms, deleted {} records", execution, count);
}
@Transactional(value = "defaultTransactionManager")
@Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 48 * ONE_MINUTE)
@SchedulerLock(name = "clearExpiredAcrs", lockAtMostFor = "3590s", lockAtLeastFor = "3590s")
public void clearExpiredAcrs() {
try {
LockAssert.assertLocked();
} catch (IllegalArgumentException e) {
return;
}
long start = System.currentTimeMillis();
int count = this.customClearTasks.clearExpiredAcrs(TimeUnit.MINUTES.toMillis(15));
long execution = System.currentTimeMillis() - start;
log.info("clearExpiredAcrs took {}ms, deleted {} records", execution, count);
}
@Transactional(value = "defaultTransactionManager")
@Scheduled(fixedDelay = 60 * ONE_MINUTE, initialDelay = 48 * ONE_MINUTE)
@SchedulerLock(name = "clearExpiredDeviceAcrs", lockAtMostFor = "3590s", lockAtLeastFor = "3590s")
public void clearExpiredDeviceAcrs() {
try {
LockAssert.assertLocked();
} catch (IllegalArgumentException e) {
return;
}
long start = System.currentTimeMillis();
int count = this.customClearTasks.clearExpiredAcrs(TimeUnit.MINUTES.toMillis(15));
long execution = System.currentTimeMillis() - start;
log.info("clearExpiredDeviceAcrs took {}ms, deleted {} records", execution, count);
}
}

View File

@ -1,81 +0,0 @@
package cz.muni.ics.oidc.server;
import cz.muni.ics.openid.connect.models.Acr;
import java.time.Instant;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository class for ACR model.
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Repository
@Transactional(value = "defaultTransactionManager")
public class PerunAcrRepository {
@PersistenceContext(unitName = "defaultPersistenceUnit")
private EntityManager manager;
public Acr getActive(String sub, String clientId, String state) {
TypedQuery<Acr> query = manager.createNamedQuery(Acr.GET_ACTIVE, Acr.class);
query.setParameter(Acr.PARAM_SUB, sub);
query.setParameter(Acr.PARAM_CLIENT_ID, clientId);
query.setParameter(Acr.PARAM_STATE, state);
query.setParameter(Acr.PARAM_EXPIRES_AT, now());
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public Acr getById(Long id) {
TypedQuery<Acr> query = manager.createNamedQuery(Acr.GET_BY_ID, Acr.class);
query.setParameter(Acr.PARAM_ID, id);
query.setParameter(Acr.PARAM_EXPIRES_AT, now());
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
@Transactional
public Acr store(Acr acr) {
Acr existing = getActive(acr.getSub(), acr.getClientId(), acr.getState());
if (existing != null) {
return existing;
} else {
Acr tmp = manager.merge(acr);
manager.flush();
return tmp;
}
}
@Transactional
public void remove(Long id) {
Acr acr = getById(id);
if (acr != null) {
manager.remove(acr);
}
}
@Transactional
public void deleteExpired() {
Query query = manager.createNamedQuery(Acr.DELETE_EXPIRED);
query.setParameter(Acr.PARAM_EXPIRES_AT, now());
query.executeUpdate();
}
private long now() {
return Instant.now().toEpochMilli();
}
}

View File

@ -1,91 +0,0 @@
package cz.muni.ics.oidc.server;
import cz.muni.ics.openid.connect.models.Acr;
import cz.muni.ics.openid.connect.models.DeviceCodeAcr;
import java.time.Instant;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository class for ACR model.
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Repository
@Transactional(value = "defaultTransactionManager")
public class PerunDeviceCodeAcrRepository {
@PersistenceContext(unitName = "defaultPersistenceUnit")
private EntityManager manager;
public DeviceCodeAcr getActiveByDeviceCode(String deviceCode) {
TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_ACTIVE_BY_DEVICE_CODE,
DeviceCodeAcr.class);
query.setParameter(DeviceCodeAcr.PARAM_DEVICE_CODE, deviceCode);
query.setParameter(Acr.PARAM_EXPIRES_AT, now());
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public DeviceCodeAcr getByUserCode(String userCode) {
TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_BY_USER_CODE, DeviceCodeAcr.class);
query.setParameter(DeviceCodeAcr.PARAM_USER_CODE, userCode);
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public DeviceCodeAcr getById(Long id) {
TypedQuery<DeviceCodeAcr> query = manager.createNamedQuery(DeviceCodeAcr.GET_BY_ID, DeviceCodeAcr.class);
query.setParameter(DeviceCodeAcr.PARAM_ID, id);
query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, now());
try {
return query.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
@Transactional
public DeviceCodeAcr store(DeviceCodeAcr acr) {
try {
return getActiveByDeviceCode(acr.getDeviceCode());
} catch (NoResultException e) {
DeviceCodeAcr tmp = manager.merge(acr);
manager.flush();
return tmp;
}
}
@Transactional
public void remove(Long id) {
DeviceCodeAcr acr = getById(id);
if (acr != null) {
manager.remove(acr);
}
}
@Transactional
public void deleteExpired() {
Query query = manager.createNamedQuery(DeviceCodeAcr.DELETE_EXPIRED);
query.setParameter(DeviceCodeAcr.PARAM_EXPIRES_AT, now());
query.executeUpdate();
}
private long now() {
return Instant.now().toEpochMilli();
}
}

View File

@ -4,17 +4,14 @@ import cz.muni.ics.oauth2.model.ClientDetailsEntity;
import cz.muni.ics.oauth2.model.DeviceCode;
import cz.muni.ics.oauth2.service.SystemScopeService;
import cz.muni.ics.oauth2.web.DeviceEndpoint;
import cz.muni.ics.oidc.server.PerunDeviceCodeAcrRepository;
import cz.muni.ics.oidc.server.PerunScopeClaimTranslationService;
import cz.muni.ics.oidc.server.configurations.PerunOidcConfig;
import cz.muni.ics.oidc.server.filters.PerunFilterConstants;
import cz.muni.ics.oidc.server.userInfo.PerunUserInfo;
import cz.muni.ics.oidc.web.WebHtmlClasses;
import cz.muni.ics.oidc.web.langs.Localization;
import cz.muni.ics.openid.connect.models.DeviceCodeAcr;
import cz.muni.ics.openid.connect.service.UserInfoService;
import java.security.Principal;
import java.time.Instant;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ -41,7 +38,6 @@ public class ApproveDeviceController {
public static final String DEVICE_APPROVED = "deviceApproved";
public static final String REQUEST_USER_CODE = "requestUserCode";
public static final String USER_CODE = "user_code";
public static final String DEVICE_CODE = "device_code";
public static final String USER_OAUTH_APPROVAL = "user_oauth_approval";
public static final String URL = "devicecode";
public static final String VERIFICATION_URI = "verification_uri";
@ -59,7 +55,6 @@ public class ApproveDeviceController {
private final WebHtmlClasses htmlClasses;
private final PerunScopeClaimTranslationService scopeClaimTranslationService;
private final UserInfoService userInfoService;
private final PerunDeviceCodeAcrRepository deviceCodeAcrRepository;
@Autowired
public ApproveDeviceController(SystemScopeService scopeService,
@ -68,8 +63,7 @@ public class ApproveDeviceController {
Localization localization,
WebHtmlClasses htmlClasses,
PerunScopeClaimTranslationService scopeClaimTranslationService,
UserInfoService userInfoService,
PerunDeviceCodeAcrRepository perunDeviceCodeAcrRepository)
UserInfoService userInfoService)
{
this.scopeService = scopeService;
this.deviceEndpoint = deviceEndpoint;
@ -78,7 +72,6 @@ public class ApproveDeviceController {
this.htmlClasses = htmlClasses;
this.scopeClaimTranslationService = scopeClaimTranslationService;
this.userInfoService = userInfoService;
this.deviceCodeAcrRepository = perunDeviceCodeAcrRepository;
}
@RequestMapping(
@ -96,7 +89,6 @@ public class ApproveDeviceController {
Map<String, Object> response = (Map<String, Object>) model.get(ENTITY);
response.replace(VERIFICATION_URI, response.get(VERIFICATION_URI) + "?" + ACR_VALUES + "=" + acrValues);
response.replace(VERIFICATION_URI_COMPLETE, response.get(VERIFICATION_URI_COMPLETE) + "&" + ACR_VALUES + "=" + acrValues);
storeAcrBase((String) response.get(DEVICE_CODE), (String)response.get(USER_CODE));
return result;
}
@ -145,10 +137,6 @@ public class ApproveDeviceController {
{
String result = deviceEndpoint.readUserCode(userCode, model, session);
if (result.equals(APPROVE_DEVICE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) {
if (StringUtils.hasText(req.getParameter(ACR))) {
storeAcr(req.getParameter(ACR), userCode);
}
return themedApproveDevice(model, p, req);
} else if (result.equals(REQUEST_USER_CODE) && !perunOidcConfig.getTheme().equalsIgnoreCase("default")) {
ControllerUtils.setPageOptions(model, req, localization, htmlClasses, perunOidcConfig);
@ -189,14 +177,6 @@ public class ApproveDeviceController {
return result;
}
private void storeAcr(String acrValue, String userCode) {
DeviceCodeAcr acr = deviceCodeAcrRepository.getByUserCode(userCode);
acr.setShibAuthnContextClass(acrValue);
long expiresAtEpoch = Instant.now().plusSeconds(600L).toEpochMilli();
acr.setExpiresAt(expiresAtEpoch);
deviceCodeAcrRepository.store(acr);
}
private String themedApproveDevice(ModelMap model, Principal p, HttpServletRequest req) {
model.remove("scopes");
DeviceCode dc = (DeviceCode) model.get("dc");
@ -210,10 +190,4 @@ public class ApproveDeviceController {
return "themedApproveDevice";
}
private void storeAcrBase(String deviceCode, String userCode) {
DeviceCodeAcr acrBase = new DeviceCodeAcr(deviceCode, userCode);
acrBase.setExpiresAt(Instant.now().plusSeconds(1800).toEpochMilli());
deviceCodeAcrRepository.store(acrBase);
}
}

View File

@ -1,137 +0,0 @@
package cz.muni.ics.openid.connect.models;
import static cz.muni.ics.openid.connect.models.Acr.PARAM_EXPIRES_AT;
import static cz.muni.ics.openid.connect.models.Acr.PARAM_SUB;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Model of ACR.
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Entity
@Table(name = "acrs")
@NamedQueries({
@NamedQuery(name = Acr.GET_ACTIVE, query = "SELECT acr FROM Acr acr WHERE " +
"acr.sub = :" + PARAM_SUB +
" AND acr.clientId = :" + Acr.PARAM_CLIENT_ID +
" AND acr.state = :" + Acr.PARAM_STATE +
" AND acr.expiresAt > :" + PARAM_EXPIRES_AT),
@NamedQuery(name = Acr.GET_BY_ID,
query = "SELECT acr FROM Acr acr " +
"WHERE acr.id = :" + Acr.PARAM_ID +
" AND acr.expiresAt > :" + PARAM_EXPIRES_AT),
@NamedQuery(name = Acr.DELETE_EXPIRED,
query = "DELETE FROM Acr acr WHERE acr.expiresAt <= :" + Acr.PARAM_EXPIRES_AT)
})
public class Acr {
public static final String GET_ACTIVE = "Acr.getActive";
public static final String GET_BY_ID = "Acr.getById";
public static final String DELETE_EXPIRED = "Acr.deleteExpired";
public static final String PARAM_ID = "id";
public static final String PARAM_SUB = "sub";
public static final String PARAM_CLIENT_ID = "client_id";
public static final String PARAM_STATE = "state";
public static final String PARAM_EXPIRES_AT = "expiration";
private Long id;
private String sub;
private String clientId;
private String state;
private String shibAuthnContextClass;
private long expiresAt;
public Acr() { }
public Acr(String sub, String clientId, String state, String shibAuthnContextClass, long expiresAt) {
this.sub = sub;
this.clientId = clientId;
this.state = state;
this.shibAuthnContextClass = shibAuthnContextClass;
this.expiresAt = expiresAt;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Basic
@Column(name = "sub")
public String getSub() {
return sub;
}
public void setSub(String sub) {
this.sub = sub;
}
@Basic
@Column(name = "client_id")
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
@Basic
@Column(name = "state")
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Basic
@Column(name = "shib_authn_context_class")
public String getShibAuthnContextClass() {
return shibAuthnContextClass;
}
public void setShibAuthnContextClass(String shibAuthnContextClass) {
this.shibAuthnContextClass = shibAuthnContextClass;
}
@Basic
@Column(name = "expiration")
public long getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(long expiresAt) {
this.expiresAt = expiresAt;
}
@Override
public String toString() {
return "Acr{" +
"id=" + id +
", sub='" + sub + '\'' +
", clientId='" + clientId + '\'' +
", state='" + state + '\'' +
", shibAuthnContextClass='" + shibAuthnContextClass + '\'' +
", expiration=" + expiresAt +
'}';
}
}

View File

@ -1,122 +0,0 @@
package cz.muni.ics.openid.connect.models;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* Model of ACR for device_code flow.
*
* @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
*/
@Entity
@Table(name = "device_code_acrs")
@NamedQueries({
@NamedQuery(name = DeviceCodeAcr.GET_ACTIVE_BY_DEVICE_CODE,
query = "SELECT acr FROM DeviceCodeAcr acr WHERE " +
"acr.deviceCode = :" + DeviceCodeAcr.PARAM_DEVICE_CODE +
" AND acr.expiresAt > :" + DeviceCodeAcr.PARAM_EXPIRES_AT),
@NamedQuery(name = DeviceCodeAcr.GET_BY_ID,
query = "SELECT acr FROM DeviceCodeAcr acr " +
"WHERE acr.id = :" + DeviceCodeAcr.PARAM_ID +
" AND acr.expiresAt > :" + DeviceCodeAcr.PARAM_EXPIRES_AT),
@NamedQuery(name = DeviceCodeAcr.GET_BY_USER_CODE,
query = "SELECT acr FROM DeviceCodeAcr acr " +
"WHERE acr.userCode = :" + DeviceCodeAcr.PARAM_USER_CODE),
@NamedQuery(name = DeviceCodeAcr.DELETE_EXPIRED,
query = "DELETE FROM DeviceCodeAcr acr WHERE acr.expiresAt <= :" + DeviceCodeAcr.PARAM_EXPIRES_AT)
})
public class DeviceCodeAcr {
public static final String GET_ACTIVE_BY_DEVICE_CODE = "DeviceCodeAcr.getActive";
public static final String GET_BY_ID = "DeviceCodeAcr.getById";
public static final String DELETE_EXPIRED = "DeviceCodeAcr.deleteExpired";
public static final String GET_BY_USER_CODE = "DeviceCodeAcr.getByUserCode";
public static final String PARAM_ID = "id";
public static final String PARAM_USER_CODE = "user_code";
public static final String PARAM_DEVICE_CODE = "device_code";
public static final String PARAM_EXPIRES_AT = "expiration";
private Long id;
private String userCode;
private String deviceCode;
private String shibAuthnContextClass;
private long expiresAt;
public DeviceCodeAcr() { }
public DeviceCodeAcr(String deviceCode, String userCode) {
this.deviceCode = deviceCode;
this.userCode = userCode;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Basic
@Column(name = "device_code")
public String getDeviceCode() {
return deviceCode;
}
public void setDeviceCode(String deviceCode) {
this.deviceCode = deviceCode;
}
@Basic
@Column(name = "user_code")
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
@Basic
@Column(name = "shib_authn_context_class")
public String getShibAuthnContextClass() {
return shibAuthnContextClass;
}
public void setShibAuthnContextClass(String shibAuthnContextClass) {
this.shibAuthnContextClass = shibAuthnContextClass;
}
@Basic
@Column(name = "expiration")
public long getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(long expiresAt) {
this.expiresAt = expiresAt;
}
@Override
public String toString() {
return "Acr{" +
"id=" + id +
", deviceCode='" + deviceCode + '\'' +
", userCode='" + userCode + '\'' +
", shibAuthnContextClass='" + shibAuthnContextClass + '\'' +
", expiration=" + expiresAt +
'}';
}
}