mirror of
https://gitee.com/dromara/MaxKey.git
synced 2026-05-15 13:02:07 +08:00
CAS REST
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
|
||||
*
|
||||
* 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.maxkey.authz.cas.endpoint;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.maxkey.authn.BasicAuthentication;
|
||||
import org.maxkey.authn.realm.AbstractAuthenticationRealm;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.CasConstants;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.ServiceTicketImpl;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.TicketGrantingTicketImpl;
|
||||
import org.maxkey.domain.UserInfo;
|
||||
import org.maxkey.domain.apps.AppsCasDetails;
|
||||
import org.maxkey.persistence.db.PasswordPolicyValidator;
|
||||
import org.maxkey.web.WebContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* @author Crystal.Sea
|
||||
* https://apereo.github.io/cas/6.2.x/protocol/REST-Protocol.html
|
||||
*/
|
||||
@Controller
|
||||
public class CasRestV1Endpoint extends CasBaseAuthorizeEndpoint{
|
||||
final static Logger _logger = LoggerFactory.getLogger(CasRestV1Endpoint.class);
|
||||
|
||||
@Autowired
|
||||
protected PasswordPolicyValidator passwordPolicyValidator;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authenticationRealm")
|
||||
protected AbstractAuthenticationRealm authenticationRealm;
|
||||
|
||||
|
||||
@RequestMapping(value="/authz/cas/v1/tickets",
|
||||
method=RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ResponseEntity<String> casLoginRestTickets(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
|
||||
@RequestParam(value=CasConstants.PARAMETER.SERVICE,required=false) String casService,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_USERNAME,required=true) String username,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_PASSWORD,required=true) String password){
|
||||
try {
|
||||
if (password == null || password.isEmpty()) {
|
||||
throw new BadCredentialsException("No credentials are provided or extracted to authenticate the REST request");
|
||||
}
|
||||
|
||||
AbstractAuthenticationRealm authenticationRealm =
|
||||
(AbstractAuthenticationRealm) WebContext.getBean("authenticationRealm");
|
||||
UserInfo loadeduserInfo = authenticationRealm.loadUserInfo(username, "");
|
||||
if (loadeduserInfo != null) {
|
||||
|
||||
authenticationRealm.passwordMatches(loadeduserInfo, password);
|
||||
|
||||
passwordPolicyValidator.passwordPolicyValid(loadeduserInfo);
|
||||
|
||||
WebContext.setUserInfo(loadeduserInfo);
|
||||
BasicAuthentication authentication =new BasicAuthentication();
|
||||
authentication.setUsername(username);
|
||||
authentication.setPassword(password);
|
||||
authentication.setAuthType("basic");
|
||||
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
authentication,
|
||||
"PASSWORD",
|
||||
authenticationRealm.grantAuthority(loadeduserInfo)
|
||||
);
|
||||
|
||||
authentication.setAuthenticated(true);
|
||||
WebContext.setAuthentication(usernamePasswordAuthenticationToken);
|
||||
WebContext.setUserInfo(loadeduserInfo);
|
||||
|
||||
authenticationRealm.insertLoginHistory(loadeduserInfo, "CAS", "", "", "SUCCESS");
|
||||
|
||||
TicketGrantingTicketImpl ticketGrantingTicket=new TicketGrantingTicketImpl("Random",WebContext.getAuthentication(),null);
|
||||
|
||||
String ticket=ticketServices.createTicket(ticketGrantingTicket);
|
||||
String location = applicationConfig.getServerPrefix()+"/authz/cas/v1/tickets/" + ticket;
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("location", location);
|
||||
return new ResponseEntity<>("Location: " + location, headers ,HttpStatus.CREATED);
|
||||
|
||||
}else {
|
||||
String message = WebContext.getI18nValue("login.error.username");
|
||||
_logger.debug("login user " + username + " not in this System ." + message);
|
||||
throw new BadCredentialsException(WebContext.getI18nValue("login.error.username"));
|
||||
}
|
||||
} catch (final AuthenticationException e) {
|
||||
_logger.error("BadCredentialsException ", e);
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
|
||||
} catch (final Exception e) {
|
||||
|
||||
_logger.error("Exception ", e);
|
||||
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value="/authz/cas/v1/tickets/{ticketGrantingTicket}",
|
||||
method=RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ResponseEntity<String> requestServiceTicket(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("ticketGrantingTicket") String ticketGrantingTicket,
|
||||
@RequestParam(value=CasConstants.PARAMETER.SERVICE,required=false) String casService,
|
||||
@RequestParam(value=CasConstants.PARAMETER.RENEW,required=false) String renew,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_USERNAME,required=false) String username,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_PASSWORD,required=false) String password){
|
||||
try {
|
||||
TicketGrantingTicketImpl ticketGrantingTicketImpl =
|
||||
(TicketGrantingTicketImpl) ticketServices.consumeTicket(ticketGrantingTicket);
|
||||
AppsCasDetails casDetails=new AppsCasDetails();
|
||||
if(casService.startsWith("http")) {
|
||||
casDetails.setService(casService);
|
||||
|
||||
List<AppsCasDetails> casDetailsList=casDetailsService.query(casDetails);
|
||||
|
||||
casDetails=(casDetailsList!=null && casDetailsList.size()==1)?casDetailsList.get(0):null;
|
||||
}else {
|
||||
casDetails=casDetailsService.getAppDetails(casService);
|
||||
}
|
||||
|
||||
ServiceTicketImpl serviceTicket=new ServiceTicketImpl(ticketGrantingTicketImpl.getAuthentication(),casDetails);
|
||||
String ticket=ticketServices.createTicket(serviceTicket);
|
||||
return new ResponseEntity<>(ticket, HttpStatus.OK);
|
||||
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new ResponseEntity<>("", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
@RequestMapping(value="/authz/cas/v1/users",
|
||||
method=RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
public ResponseEntity<String> casLoginRestUsers(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@RequestParam(value=CasConstants.PARAMETER.SERVICE,required=false) String casService,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_USERNAME,required=true) String username,
|
||||
@RequestParam(value=CasConstants.PARAMETER.REST_PASSWORD,required=true) String password){
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,10 @@ public class CasConstants {
|
||||
|
||||
/** Constant representing the pgtIou parameter in the request. */
|
||||
public static final String PROXY_GRANTING_TICKET_IOU = "pgtIou";
|
||||
|
||||
public static final String REST_USERNAME = "username";
|
||||
|
||||
public static final String REST_PASSWORD = "password";
|
||||
}
|
||||
|
||||
public static final class FORMAT_TYPE {
|
||||
@@ -83,6 +87,8 @@ public class CasConstants {
|
||||
public static final String PROXY_GRANTING_TICKET_PREFIX = "PGT";
|
||||
/** The prefix to use when generating an id for a Proxy Granting Ticket IOU. */
|
||||
public static final String PROXY_GRANTING_TICKET_IOU_PREFIX = "PGTIOU";
|
||||
|
||||
public static final String TICKET_GRANTING_TICKET_PREFIX = "TGT";
|
||||
}
|
||||
|
||||
/* CAS Protocol Error Codes. **/
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Strategy that determines if the ticket is expired. Implementations of the
|
||||
* Expiration Policy define their own rules on what they consider an expired
|
||||
* Ticket to be.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @see Ticket
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public interface ExpirationPolicy extends Serializable {
|
||||
|
||||
/**
|
||||
* Method to determine if a Ticket has expired or not, based on the policy.
|
||||
*
|
||||
* @param ticketState The snapshot of the current ticket state
|
||||
* @return true if the ticket is expired, false otherwise.
|
||||
*/
|
||||
boolean isExpired(TicketState ticketState);
|
||||
|
||||
/**
|
||||
* Method to determine the actual TTL of a ticket, based on the policy.
|
||||
*
|
||||
* @param ticketState The snapshot of the current ticket state
|
||||
* @return The time to live in seconds. A zero value indicates the time duration is not supported or is inactive.
|
||||
*/
|
||||
default Long getTimeToLive(final TicketState ticketState) {
|
||||
return getTimeToLive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the time duration where this policy should consider the item alive.
|
||||
* Once this time passes, the item is considered expired and dead.
|
||||
*
|
||||
* @return time to live in seconds. A zero value indicates the time duration is not supported or is inactive.
|
||||
*/
|
||||
Long getTimeToLive();
|
||||
|
||||
/**
|
||||
* Describes the idle time duration for the item.
|
||||
*
|
||||
* @return idle time in seconds. A zero value indicates the time duration is not supported or is inactive. Unit of measure is defined by the implementation.
|
||||
*/
|
||||
Long getTimeToIdle();
|
||||
|
||||
/**
|
||||
* Gets name of this expiration policy.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import org.maxkey.authz.cas.endpoint.ticket.proxy.ProxyGrantingTicket;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
/**
|
||||
* Interface for a Service Ticket. A service ticket is used to grant access to a
|
||||
* specific service for a principal. A Service Ticket is generally a one-time
|
||||
* use ticket.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include= JsonTypeInfo.As.PROPERTY)
|
||||
public interface ServiceTicket extends Ticket {
|
||||
|
||||
/**
|
||||
* Prefix generally applied to unique ids generated
|
||||
* by UniqueTicketIdGenerator.
|
||||
*/
|
||||
String PREFIX = "ST";
|
||||
|
||||
/**
|
||||
* Retrieve the service this ticket was given for.
|
||||
*
|
||||
* @return the server.
|
||||
*/
|
||||
Service getService();
|
||||
|
||||
/**
|
||||
* Determine if this ticket was created at the same time as a
|
||||
* TicketGrantingTicket.
|
||||
*
|
||||
* @return true if it is, false otherwise.
|
||||
*/
|
||||
boolean isFromNewLogin();
|
||||
|
||||
/**
|
||||
* Attempts to ensure that the service specified matches the service associated with the ticket.
|
||||
*
|
||||
* @param service The incoming service to match this service ticket against.
|
||||
* @return true, if the match is successful.
|
||||
*/
|
||||
boolean isValidFor(Service service);
|
||||
|
||||
/**
|
||||
* Method to grant a TicketGrantingTicket from this service to the
|
||||
* authentication. Analogous to the ProxyGrantingTicket.
|
||||
*
|
||||
* @param id The unique identifier for this ticket.
|
||||
* @param authentication The Authentication we wish to grant a ticket for.
|
||||
* @param expirationPolicy expiration policy associated with this ticket
|
||||
* @return The ticket granting ticket.
|
||||
* @throws AbstractTicketException ticket exception thrown when generating the ticket
|
||||
* @since 4.2
|
||||
*/
|
||||
ProxyGrantingTicket grantProxyGrantingTicket(String id,
|
||||
Authentication authentication,
|
||||
ExpirationPolicy expirationPolicy)
|
||||
throws Exception;
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.proxy.ProxyGrantingTicket;
|
||||
import org.maxkey.domain.apps.AppsCasDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
@@ -33,7 +34,7 @@ import javax.persistence.Column;
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
public class ServiceTicketImpl extends AbstractTicket {
|
||||
public class ServiceTicketImpl extends AbstractTicket implements ServiceTicket{
|
||||
|
||||
private static final long serialVersionUID = -4223319704861765405L;
|
||||
|
||||
@@ -112,4 +113,23 @@ public class ServiceTicketImpl extends AbstractTicket {
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Service getService() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromNewLogin() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxyGrantingTicket grantProxyGrantingTicket(String id, Authentication authentication,
|
||||
ExpirationPolicy expirationPolicy) throws Exception {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.maxkey.domain.apps.AppsCasDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* Interface for a ticket granting ticket. A TicketGrantingTicket is the main
|
||||
* access into the CAS service layer. Without a TicketGrantingTicket, a user of
|
||||
* CAS cannot do anything.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public interface TicketGrantingTicket extends Ticket {
|
||||
|
||||
/**
|
||||
* The prefix to use when generating an id for a Ticket Granting Ticket.
|
||||
*/
|
||||
String PREFIX = "TGT";
|
||||
|
||||
/**
|
||||
* Method to retrieve the authentication.
|
||||
*
|
||||
* @return the authentication
|
||||
*/
|
||||
Authentication getAuthentication();
|
||||
|
||||
/**
|
||||
* Grant a ServiceTicket for a specific service.
|
||||
*
|
||||
* @param id The unique identifier for this ticket.
|
||||
* @param service The service for which we are granting a ticket
|
||||
* @param expirationPolicy the expiration policy.
|
||||
* @param credentialProvided current credential event for issuing this ticket. Could be null.
|
||||
* @param onlyTrackMostRecentSession track the most recent session by keeping the latest service ticket
|
||||
* @return the service ticket granted to a specific service for the principal of the TicketGrantingTicket
|
||||
*/
|
||||
ServiceTicket grantServiceTicket(String id, Service service,
|
||||
AppsCasDetails casDetails,
|
||||
ExpirationPolicy expirationPolicy,
|
||||
boolean credentialProvided,
|
||||
boolean onlyTrackMostRecentSession);
|
||||
|
||||
/**
|
||||
* Gets an immutable map of service ticket and services accessed by this ticket-granting ticket.
|
||||
*
|
||||
* @return an immutable map of service ticket and services accessed by this ticket-granting ticket.
|
||||
*/
|
||||
Map<String, Service> getServices();
|
||||
|
||||
/**
|
||||
* Gets proxy granting tickets created by this TGT.
|
||||
*
|
||||
* @return the proxy granting tickets
|
||||
*/
|
||||
Map<String, Service> getProxyGrantingTickets();
|
||||
|
||||
/**
|
||||
* Remove all services of the TGT (at logout).
|
||||
*/
|
||||
void removeAllServices();
|
||||
|
||||
/**
|
||||
* Convenience method to determine if the TicketGrantingTicket is the root
|
||||
* of the hierarchy of tickets.
|
||||
*
|
||||
* @return true if it has no parent, false otherwise.
|
||||
*/
|
||||
boolean isRoot();
|
||||
|
||||
/**
|
||||
* Gets the ticket-granting ticket at the root of the ticket hierarchy.
|
||||
*
|
||||
* @return Non -null root ticket-granting ticket.
|
||||
*/
|
||||
TicketGrantingTicket getRoot();
|
||||
|
||||
/**
|
||||
* Gets all authentications ({@link #getAuthentication()} from this
|
||||
* instance and all dependent tickets that reference this one.
|
||||
*
|
||||
* @return Non -null list of authentication associated with this ticket in leaf-first order.
|
||||
*/
|
||||
List<Authentication> getChainedAuthentications();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the service that produced a proxy-granting ticket.
|
||||
*
|
||||
* @return Service that produced proxy-granting ticket or null if this is not a proxy-granting ticket.
|
||||
* @since 4.1
|
||||
*/
|
||||
Service getProxiedBy();
|
||||
|
||||
/**
|
||||
* Gets descendant tickets. These are generally ticket ids
|
||||
* whose life-line is separate from the TGT until and unless
|
||||
* the TGT goes away entirely. Things such as OAuth access tokens
|
||||
* are a good example of such linked tickets.
|
||||
*
|
||||
* @return the descendant tickets
|
||||
* @since 5.1
|
||||
*/
|
||||
default Collection<String> getDescendantTickets() {
|
||||
return new HashSet<>(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.maxkey.domain.apps.AppsCasDetails;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Concrete implementation of a TicketGrantingTicket. A TicketGrantingTicket is
|
||||
* the global identifier of a principal into the system. It grants the Principal
|
||||
* single-sign on access to any service that opts into single-sign on.
|
||||
* Expiration of a TicketGrantingTicket is controlled by the ExpirationPolicy
|
||||
* specified as object creation.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "TICKETGRANTINGTICKET")
|
||||
@DiscriminatorColumn(name = "TYPE")
|
||||
@DiscriminatorValue(TicketGrantingTicket.PREFIX)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
|
||||
public class TicketGrantingTicketImpl extends AbstractTicket implements TicketGrantingTicket {
|
||||
|
||||
/**
|
||||
* Unique Id for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = -8608149809180911599L;
|
||||
|
||||
/**
|
||||
* The authenticated object for which this ticket was generated for.
|
||||
*/
|
||||
@Lob
|
||||
@Column(name = "AUTHENTICATION", nullable = false, length = Integer.MAX_VALUE)
|
||||
private Authentication authentication;
|
||||
|
||||
/**
|
||||
* Service that produced a proxy-granting ticket.
|
||||
*/
|
||||
@Lob
|
||||
@Column(name = "PROXIED_BY", length = Integer.MAX_VALUE)
|
||||
private Service proxiedBy;
|
||||
|
||||
/**
|
||||
* The services associated to this ticket.
|
||||
*/
|
||||
@Lob
|
||||
@Column(name = "SERVICES_GRANTED_ACCESS_TO", nullable = false, length = Integer.MAX_VALUE)
|
||||
private HashMap<String, Service> services = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The {@link TicketGrantingTicket} this is associated with.
|
||||
*/
|
||||
@ManyToOne(targetEntity = TicketGrantingTicketImpl.class)
|
||||
private TicketGrantingTicket ticketGrantingTicket;
|
||||
|
||||
/**
|
||||
* The PGTs associated to this ticket.
|
||||
*/
|
||||
@Lob
|
||||
@Column(name = "PROXY_GRANTING_TICKETS", nullable = false, length = Integer.MAX_VALUE)
|
||||
private HashMap<String, Service> proxyGrantingTickets = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The ticket ids which are tied to this ticket.
|
||||
*/
|
||||
@Lob
|
||||
@Column(name = "DESCENDANT_TICKETS", nullable = false, length = Integer.MAX_VALUE)
|
||||
private HashSet<String> descendantTickets = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Constructs a new TicketGrantingTicket.
|
||||
* May throw an {@link IllegalArgumentException} if the Authentication object is null.
|
||||
*
|
||||
* @param id the id of the Ticket
|
||||
* @param proxiedBy Service that produced this proxy ticket.
|
||||
* @param parentTicketGrantingTicket the parent ticket
|
||||
* @param authentication the Authentication request for this ticket
|
||||
* @param policy the expiration policy for this ticket.
|
||||
*/
|
||||
@JsonCreator
|
||||
public TicketGrantingTicketImpl(@JsonProperty("id") final String id, @JsonProperty("proxiedBy") final Service proxiedBy,
|
||||
@JsonProperty("ticketGrantingTicket") final TicketGrantingTicket parentTicketGrantingTicket,
|
||||
@NonNull @JsonProperty("authentication") final Authentication authentication, @JsonProperty("expirationPolicy") final ExpirationPolicy policy) {
|
||||
if (parentTicketGrantingTicket != null && proxiedBy == null) {
|
||||
throw new IllegalArgumentException("Must specify proxiedBy when providing parent TGT");
|
||||
}
|
||||
this.ticketGrantingTicket = parentTicketGrantingTicket;
|
||||
this.authentication = authentication;
|
||||
this.proxiedBy = proxiedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new TicketGrantingTicket without a parent
|
||||
* TicketGrantingTicket.
|
||||
*
|
||||
* @param id the id of the Ticket
|
||||
* @param authentication the Authentication request for this ticket
|
||||
* @param policy the expiration policy for this ticket.
|
||||
*/
|
||||
public TicketGrantingTicketImpl(final String id, final Authentication authentication, final ExpirationPolicy policy) {
|
||||
this(id, null, null, authentication, policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ServiceTicket grantServiceTicket(final String id, final Service service, AppsCasDetails casDetails,final ExpirationPolicy expirationPolicy,
|
||||
final boolean credentialProvided, final boolean onlyTrackMostRecentSession) {
|
||||
final ServiceTicket serviceTicket = new ServiceTicketImpl(authentication,casDetails);
|
||||
return serviceTicket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the path of a service by removing the query string and everything after a semi-colon.
|
||||
*
|
||||
* @param service the service to normalize
|
||||
* @return the normalized path
|
||||
|
||||
private static String normalizePath(final Service service) {
|
||||
String path = service.getId();
|
||||
path = StringUtils.substringBefore(path, "?");
|
||||
path = StringUtils.substringBefore(path, ";");
|
||||
path = StringUtils.substringBefore(path, "#");
|
||||
return path;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Remove all services of the TGT (at logout).
|
||||
*/
|
||||
@Override
|
||||
public void removeAllServices() {
|
||||
this.services.clear();
|
||||
}
|
||||
|
||||
|
||||
public String getPrefix() {
|
||||
return TicketGrantingTicket.PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Service> getServices() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Service> getProxyGrantingTickets() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Service getProxiedBy() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRoot() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TicketGrantingTicket getRoot() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Authentication> getChainedAuthentications() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
* @author Scott Battaglia
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public interface TicketState {
|
||||
|
||||
/**
|
||||
* Returns the number of times a ticket was used.
|
||||
*
|
||||
* @return the number of times the ticket was used.
|
||||
*/
|
||||
int getCountOfUses();
|
||||
|
||||
/**
|
||||
* Returns the last time the ticket was used.
|
||||
*
|
||||
* @return the last time the ticket was used.
|
||||
*/
|
||||
ZonedDateTime getLastTimeUsed();
|
||||
|
||||
/**
|
||||
* Get the second to last time used.
|
||||
*
|
||||
* @return the previous time used.
|
||||
*/
|
||||
ZonedDateTime getPreviousTimeUsed();
|
||||
|
||||
/**
|
||||
* Get the time the ticket was created.
|
||||
*
|
||||
* @return the creation time of the ticket.
|
||||
*/
|
||||
ZonedDateTime getCreationTime();
|
||||
|
||||
/**
|
||||
* Authentication information from the ticket. This may be null.
|
||||
*
|
||||
* @return the authentication information.
|
||||
*/
|
||||
Authentication getAuthentication();
|
||||
|
||||
/**
|
||||
* Method to retrieve the TicketGrantingTicket that granted this ticket.
|
||||
*
|
||||
* @return the ticket or null if it has no parent
|
||||
*/
|
||||
TicketGrantingTicket getTicketGrantingTicket();
|
||||
|
||||
/**
|
||||
* Records the <i>previous</i> last time this ticket was used as well as
|
||||
* the last usage time. The ticket usage count is also incremented.
|
||||
* <p>Tickets themselves are solely responsible to maintain their state. The
|
||||
* determination of ticket usage is left up to the implementation and
|
||||
* the specific ticket type.
|
||||
*
|
||||
* @see ExpirationPolicy
|
||||
* @since 5.0.0
|
||||
*/
|
||||
void update();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket.proxy;
|
||||
|
||||
import org.maxkey.authz.cas.endpoint.ticket.ExpirationPolicy;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.Service;
|
||||
import org.maxkey.authz.cas.endpoint.ticket.TicketGrantingTicket;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
/**
|
||||
* Interface for a proxy granting ticket. A proxy-granting ticket is an opaque string that is
|
||||
* used by a service to obtain proxy tickets for obtaining access to a back-end service on behalf of a client.
|
||||
* Proxy-granting tickets are obtained from CAS upon validation of a service ticket or a proxy ticket.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public interface ProxyGrantingTicket extends TicketGrantingTicket {
|
||||
|
||||
/** The prefix to use when generating an id for a Proxy Granting Ticket. */
|
||||
String PROXY_GRANTING_TICKET_PREFIX = "PGT";
|
||||
|
||||
/** The prefix to use when generating an id for a Proxy Granting Ticket IOU. */
|
||||
String PROXY_GRANTING_TICKET_IOU_PREFIX = "PGTIOU";
|
||||
|
||||
/**
|
||||
* Grant a proxy ticket for a specific service.
|
||||
*
|
||||
* @param id The unique identifier for this ticket.
|
||||
* @param service The service for which we are granting a ticket
|
||||
* @param expirationPolicy the expiration policy.
|
||||
* @param onlyTrackMostRecentSession track the most recent session by keeping the latest service ticket
|
||||
* @return the service ticket granted to a specific service for the
|
||||
* principal of the TicketGrantingTicket
|
||||
*/
|
||||
ProxyTicket grantProxyTicket(String id, Service service,
|
||||
ExpirationPolicy expirationPolicy,
|
||||
boolean onlyTrackMostRecentSession);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.maxkey.authz.cas.endpoint.ticket.proxy;
|
||||
|
||||
import org.maxkey.authz.cas.endpoint.ticket.ServiceTicket;
|
||||
|
||||
/**
|
||||
* The {@link ProxyTicket} represents a CAS proxy ticket. A proxy ticket is an opaque string that a
|
||||
* service uses as a credential to obtain access to a back-end service on behalf of a client.
|
||||
* Proxy tickets are obtained from CAS upon a service’s
|
||||
* presentation of a valid {@link ProxyGrantingTicket}
|
||||
* and a service identifier for the back-end service to which it is connecting.
|
||||
*
|
||||
* @author Misagh Moayyed
|
||||
* @since 4.2
|
||||
*/
|
||||
public interface ProxyTicket extends ServiceTicket {
|
||||
/** Proxy ticket prefix applied to unique ids. */
|
||||
String PROXY_TICKET_PREFIX = "PT";
|
||||
}
|
||||
@@ -46,9 +46,9 @@ public abstract class RandomServiceTicketServices implements TicketServices {
|
||||
ticketId = generator.getNewTicketId(CasConstants.PREFIX.SERVICE_TICKET_PREFIX);
|
||||
}else if(ticket.getClass().getSimpleName().equalsIgnoreCase("ProxyTicketImpl")){
|
||||
ticketId = generator.getNewTicketId(CasConstants.PREFIX.PROXY_TICKET_PREFIX);
|
||||
}else if(ticket.getClass().getSimpleName().equalsIgnoreCase("ProxyTicketImpl")){
|
||||
ticketId = generator.getNewTicketId(CasConstants.PREFIX.PROXY_TICKET_PREFIX);
|
||||
}else if(ticket.getClass().getSimpleName().equalsIgnoreCase("ProxyTicketImpl")){
|
||||
}else if(ticket.getClass().getSimpleName().equalsIgnoreCase("TicketGrantingTicketImpl")){
|
||||
ticketId = generator.getNewTicketId(CasConstants.PREFIX.TICKET_GRANTING_TICKET_PREFIX);
|
||||
}else {
|
||||
ticketId = generator.getNewTicketId(CasConstants.PREFIX.PROXY_TICKET_PREFIX);
|
||||
}
|
||||
store(ticketId, ticket);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class RedisTicketServices extends RandomServiceTicketServices {
|
||||
|
||||
RedisConnectionFactory connectionFactory;
|
||||
|
||||
public static String PREFIX="REDIS_CAS_SERVICE_TICKET_";
|
||||
public static String PREFIX="REDIS_CAS_TICKET_";
|
||||
/**
|
||||
* @param connectionFactory
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user