@Test public void verifyValidServiceTicketWithValidPgtAndProxyHandlerFailing() throws Exception { final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); final ServiceTicket sId = getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService().getId()); request.addParameter("ticket", sId.getId()); request.addParameter("pgtUrl", "https://www.github.com"); this.serviceValidateController.setProxyHandler( new ProxyHandler() { @Override public String handle( final Credential credential, final TicketGrantingTicket proxyGrantingTicketId) { return null; } @Override public boolean canHandle(final Credential credential) { return true; } }); final ModelAndView modelAndView = this.serviceValidateController.handleRequestInternal( request, new MockHttpServletResponse()); assertEquals( ServiceValidateController.DEFAULT_SERVICE_FAILURE_VIEW_NAME, modelAndView.getViewName()); assertNull(modelAndView.getModel().get("pgtIou")); }
private void internalProxyTest(final String proxyUrl) throws MalformedURLException { final Credential proxyCredential = new HttpBasedServiceCredential( new URL(proxyUrl), TestUtils.getRegisteredService("https://.+")); final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket(TGT_ID, proxyCredential, this.principalAttributes); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); }
@Test public void verifyEncodeDecodeTGTWithUnmodifiableMap() throws Exception { final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket( TGT_ID, userPassCredential, Collections.unmodifiableMap(this.principalAttributes)); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); }
@Test public void verifyEncodeDecodeTGTWithListOrderedMap() throws Exception { final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); @SuppressWarnings("unchecked") final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket(TGT_ID, userPassCredential, this.principalAttributes); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); }
@Test public void verifyEncodeDecodeTGTWithSingletonMap() throws Exception { final Map<String, Object> newAttributes = Collections.singletonMap(NICKNAME_KEY, (Object) NICKNAME_VALUE); final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket(TGT_ID, userPassCredential, newAttributes); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); }
@Test public void verifyEncodeDecodeTGTWithUnmodifiableSet() throws Exception { final Map<String, Object> newAttributes = new HashMap<>(); final Set<String> values = new HashSet<>(); values.add(NICKNAME_VALUE); newAttributes.put(NICKNAME_KEY, Collections.unmodifiableSet(values)); final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket(TGT_ID, userPassCredential, newAttributes); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); }
@Override protected ModelAndView handleRequestInternal( final HttpServletRequest request, final HttpServletResponse response) throws Exception { String accessToken = request.getParameter(OAuthConstants.ACCESS_TOKEN); if (StringUtils.isBlank(accessToken)) { final String authHeader = request.getHeader("Authorization"); if (StringUtils.isNotBlank(authHeader) && authHeader.toLowerCase().startsWith(OAuthConstants.BEARER_TOKEN.toLowerCase() + ' ')) { accessToken = authHeader.substring(OAuthConstants.BEARER_TOKEN.length() + 1); } } LOGGER.debug("{} : {}", OAuthConstants.ACCESS_TOKEN, accessToken); try (final JsonGenerator jsonGenerator = this.jsonFactory.createJsonGenerator(response.getWriter())) { response.setContentType("application/json"); // accessToken is required if (StringUtils.isBlank(accessToken)) { LOGGER.error("Missing {}", OAuthConstants.ACCESS_TOKEN); jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("error", OAuthConstants.MISSING_ACCESS_TOKEN); jsonGenerator.writeEndObject(); return null; } // get ticket granting ticket final TicketGrantingTicket ticketGrantingTicket = (TicketGrantingTicket) this.ticketRegistry.getTicket(accessToken); if (ticketGrantingTicket == null || ticketGrantingTicket.isExpired()) { LOGGER.error("expired accessToken : {}", accessToken); jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("error", OAuthConstants.EXPIRED_ACCESS_TOKEN); jsonGenerator.writeEndObject(); return null; } // generate profile : identifier + attributes final Principal principal = ticketGrantingTicket.getAuthentication().getPrincipal(); jsonGenerator.writeStartObject(); jsonGenerator.writeStringField(ID, principal.getId()); jsonGenerator.writeObjectFieldStart(ATTRIBUTES); final Map<String, Object> attributes = principal.getAttributes(); for (final Map.Entry<String, Object> entry : attributes.entrySet()) { // jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(entry.getKey(), entry.getValue()); // jsonGenerator.writeEndObject(); } // jsonGenerator.writeEndArray(); jsonGenerator.writeEndObject(); return null; } finally { response.flushBuffer(); } }
@Test public void verifyEncodeDecode() throws Exception { final ServiceTicket expectedST = new MockServiceTicket(ST_ID); assertEquals(expectedST, transcoder.decode(transcoder.encode(expectedST))); final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); final TicketGrantingTicket expectedTGT = new MockTicketGrantingTicket(TGT_ID, userPassCredential, this.principalAttributes); expectedTGT.grantServiceTicket(ST_ID, null, null, false, true); assertEquals(expectedTGT, transcoder.decode(transcoder.encode(expectedTGT))); internalProxyTest("http://localhost"); internalProxyTest("https://localhost:8080/path/file.html?p1=v1&p2=v2#fragment"); }
@Audit( action = "PROXY_GRANTING_TICKET", actionResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOLVER", resourceResolverName = "GRANT_PROXY_GRANTING_TICKET_RESOURCE_RESOLVER") @Profiled(tag = "GRANT_PROXY_GRANTING_TICKET", logFailuresSeparately = false) @Transactional(readOnly = false) @Override public String delegateTicketGrantingTicket( final String serviceTicketId, final Credential... credentials) throws AuthenticationException, TicketException { Assert.notNull(serviceTicketId, "serviceTicketId cannot be null"); Assert.notNull(credentials, "credentials cannot be null"); final ServiceTicket serviceTicket = this.serviceTicketRegistry.getTicket(serviceTicketId, ServiceTicket.class); if (serviceTicket == null || serviceTicket.isExpired()) { logger.debug( "ServiceTicket [{}] has expired or cannot be found in the ticket registry", serviceTicketId); throw new InvalidTicketException(serviceTicketId); } final RegisteredService registeredService = this.servicesManager.findServiceBy(serviceTicket.getService()); verifyRegisteredServiceProperties(registeredService, serviceTicket.getService()); if (!registeredService.isAllowedToProxy()) { logger.warn( "ServiceManagement: Service [{}] attempted to proxy, but is not allowed.", serviceTicket.getService().getId()); throw new UnauthorizedProxyingException(); } final Authentication authentication = this.authenticationManager.authenticate(credentials); final TicketGrantingTicket ticketGrantingTicket = serviceTicket.grantTicketGrantingTicket( this.ticketGrantingTicketUniqueTicketIdGenerator.getNewTicketId( TicketGrantingTicket.PREFIX), authentication, this.ticketGrantingTicketExpirationPolicy); this.ticketRegistry.addTicket(ticketGrantingTicket); return ticketGrantingTicket.getId(); }
private HttpServletRequest getHttpServletRequest() throws Exception { final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final ServiceTicket sId2 = getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService().getId()); request.addParameter("ticket", sId2.getId()); request.addParameter("renew", "true"); return request; }
/** * Gets the authentication satisfied by policy. * * @param ticket the ticket * @param context the context * @return the authentication satisfied by policy * @throws org.jasig.cas.ticket.TicketException the ticket exception */ private Authentication getAuthenticationSatisfiedByPolicy( final TicketGrantingTicket ticket, final ServiceContext context) throws TicketException { final ContextualAuthenticationPolicy<ServiceContext> policy = serviceContextAuthenticationPolicyFactory.createPolicy(context); if (policy.isSatisfiedBy(ticket.getAuthentication())) { return ticket.getAuthentication(); } for (final Authentication auth : ticket.getSupplementalAuthentications()) { if (policy.isSatisfiedBy(auth)) { return auth; } } throw new UnsatisfiedAuthenticationPolicyException(policy); }
@Test public void verifyEncodeDecodeTGTImpl() throws Exception { final Credential userPassCredential = new UsernamePasswordCredential(USERNAME, PASSWORD); final AuthenticationBuilder bldr = new DefaultAuthenticationBuilder( new DefaultPrincipalFactory() .createPrincipal("user", Collections.unmodifiableMap(this.principalAttributes))); bldr.setAttributes(Collections.unmodifiableMap(this.principalAttributes)); bldr.setAuthenticationDate(new DateTime()); bldr.addCredential(new BasicCredentialMetaData(userPassCredential)); bldr.addFailure("error", AccountNotFoundException.class); bldr.addSuccess( "authn", new DefaultHandlerResult( new AcceptUsersAuthenticationHandler(), new BasicCredentialMetaData(userPassCredential))); final TicketGrantingTicket parent = new TicketGrantingTicketImpl( TGT_ID, org.jasig.cas.authentication.TestUtils.getService(), null, bldr.build(), new NeverExpiresExpirationPolicy()); final TicketGrantingTicket expectedTGT = new TicketGrantingTicketImpl( TGT_ID, org.jasig.cas.services.TestUtils.getService(), null, bldr.build(), new NeverExpiresExpirationPolicy()); final ServiceTicket ticket = expectedTGT.grantServiceTicket( ST_ID, org.jasig.cas.services.TestUtils.getService(), new NeverExpiresExpirationPolicy(), false, true); CachedData result = transcoder.encode(expectedTGT); final TicketGrantingTicket resultTicket = (TicketGrantingTicket) transcoder.decode(result); assertEquals(expectedTGT, resultTicket); result = transcoder.encode(ticket); final ServiceTicket resultStTicket = (ServiceTicket) transcoder.decode(result); assertEquals(ticket, resultStTicket); }
protected final ModelAndView getModelAndViewUponServiceValidationWithSecurePgtUrl() throws Exception { final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); final ServiceTicket sId = getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService().getId()); request.addParameter("ticket", sId.getId()); request.addParameter("pgtUrl", "https://www.github.com"); return this.serviceValidateController.handleRequestInternal( request, new MockHttpServletResponse()); }
@Test public void verifyValidServiceTicket() throws Exception { final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); final ServiceTicket sId = getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService().getId()); request.addParameter("ticket", sId.getId()); assertEquals( ServiceValidateController.DEFAULT_SERVICE_SUCCESS_VIEW_NAME, this.serviceValidateController .handleRequestInternal(request, new MockHttpServletResponse()) .getViewName()); }
@Override protected ModelAndView handleRequestInternal( final HttpServletRequest request, final HttpServletResponse response) throws Exception { // get CAS ticket final String ticket = request.getParameter(OAuthConstants.TICKET); log.debug("ticket : {}", ticket); ServiceTicket serviceTicket = (ServiceTicket) ticketRegistry.getTicket(ticket); TicketGrantingTicket grantingTicket = serviceTicket.getGrantingTicket(); log.debug("granting ticket : {}", grantingTicket); if (grantingTicket == null) return null; // retrieve callback url from session final HttpSession session = request.getSession(); String callbackUrl = (String) session.getAttribute(OAuthConstants.OAUTH20_CALLBACKURL); log.debug("callbackUrl : {}", callbackUrl); session.removeAttribute(OAuthConstants.OAUTH20_CALLBACKURL); // and state final String state = (String) session.getAttribute(OAuthConstants.OAUTH20_STATE); log.debug("state : {}", state); session.removeAttribute(OAuthConstants.OAUTH20_STATE); if (callbackUrl == null) return null; // return callback url with code & state callbackUrl = OAuthUtils.addParameter(callbackUrl, OAuthConstants.CODE, ticket); if (state != null) { callbackUrl = OAuthUtils.addParameter(callbackUrl, OAuthConstants.STATE, state); } log.debug("callbackUrl : {}", callbackUrl); final Map<String, Object> model = new HashMap<String, Object>(); model.put("callbackUrl", callbackUrl); // retrieve service name from session final String serviceName = (String) session.getAttribute(OAuthConstants.OAUTH20_SERVICE_NAME); log.debug("serviceName : {}", serviceName); model.put("serviceName", serviceName); model.put("userId", grantingTicket.getAuthentication().getPrincipal().getId()); return new ModelAndView(OAuthConstants.CONFIRM_VIEW, model); }
@Test public void verifyValidServiceTicketWithValidPgtAndProxyHandling() throws Exception { final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); final ServiceTicket sId = getCentralAuthenticationService().grantServiceTicket(tId.getId(), TestUtils.getService()); final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService().getId()); request.addParameter("ticket", sId.getId()); request.addParameter("pgtUrl", "https://www.github.com"); final ModelAndView modelAndView = this.serviceValidateController.handleRequestInternal( request, new MockHttpServletResponse()); assertEquals( ServiceValidateController.DEFAULT_SERVICE_SUCCESS_VIEW_NAME, modelAndView.getViewName()); assertNotNull(modelAndView.getModel().get("pgtIou")); }
@Test public void verifyValidServiceTicketWithDifferentEncoding() throws Exception { this.serviceValidateController.setProxyHandler(new Cas10ProxyHandler()); final TicketGrantingTicket tId = getCentralAuthenticationService() .createTicketGrantingTicket(TestUtils.getCredentialsWithSameUsernameAndPassword()); final String origSvc = "http://www.jasig.org?param=hello+world"; final ServiceTicket sId = getCentralAuthenticationService() .grantServiceTicket(tId.getId(), TestUtils.getService(origSvc)); final String reqSvc = "http://www.jasig.org?param=hello%20world"; final MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter("service", TestUtils.getService(reqSvc).getId()); request.addParameter("ticket", sId.getId()); assertEquals( ServiceValidateController.DEFAULT_SERVICE_SUCCESS_VIEW_NAME, this.serviceValidateController .handleRequestInternal(request, new MockHttpServletResponse()) .getViewName()); }
@Audit( action = "TICKET_GRANTING_TICKET", actionResolverName = "CREATE_TICKET_GRANTING_TICKET_RESOLVER", resourceResolverName = "CREATE_TICKET_GRANTING_TICKET_RESOURCE_RESOLVER") @Profiled(tag = "CREATE_TICKET_GRANTING_TICKET", logFailuresSeparately = false) @Transactional(readOnly = false) @Override public String createTicketGrantingTicket(final Credential... credentials) throws AuthenticationException, TicketException { Assert.notNull(credentials, "credentials cannot be null"); final Authentication authentication = this.authenticationManager.authenticate(credentials); final TicketGrantingTicket ticketGrantingTicket = new TicketGrantingTicketImpl( this.ticketGrantingTicketUniqueTicketIdGenerator.getNewTicketId( TicketGrantingTicket.PREFIX), authentication, this.ticketGrantingTicketExpirationPolicy); this.ticketRegistry.addTicket(ticketGrantingTicket); return ticketGrantingTicket.getId(); }
/** * Gets sso sessions. * * @param option the option * @return the sso sessions */ private Collection<Map<String, Object>> getActiveSsoSessions( final SsoSessionReportOptions option) { final Collection<Map<String, Object>> activeSessions = new ArrayList<>(); final ISOStandardDateFormat dateFormat = new ISOStandardDateFormat(); for (final Ticket ticket : getNonExpiredTicketGrantingTickets()) { final TicketGrantingTicket tgt = (TicketGrantingTicket) ticket; if (option == SsoSessionReportOptions.DIRECT && tgt.getProxiedBy() != null) { continue; } final Authentication authentication = tgt.getAuthentication(); final Principal principal = authentication.getPrincipal(); final Map<String, Object> sso = new HashMap<>(SsoSessionAttributeKeys.values().length); sso.put(SsoSessionAttributeKeys.AUTHENTICATED_PRINCIPAL.toString(), principal.getId()); sso.put( SsoSessionAttributeKeys.AUTHENTICATION_DATE.toString(), authentication.getAuthenticationDate()); sso.put( SsoSessionAttributeKeys.AUTHENTICATION_DATE_FORMATTED.toString(), dateFormat.format(authentication.getAuthenticationDate())); sso.put(SsoSessionAttributeKeys.NUMBER_OF_USES.toString(), tgt.getCountOfUses()); sso.put(SsoSessionAttributeKeys.TICKET_GRANTING_TICKET.toString(), tgt.getId()); sso.put(SsoSessionAttributeKeys.PRINCIPAL_ATTRIBUTES.toString(), principal.getAttributes()); sso.put( SsoSessionAttributeKeys.AUTHENTICATION_ATTRIBUTES.toString(), authentication.getAttributes()); if (option != SsoSessionReportOptions.DIRECT) { if (tgt.getProxiedBy() != null) { sso.put(SsoSessionAttributeKeys.IS_PROXIED.toString(), Boolean.TRUE); sso.put(SsoSessionAttributeKeys.PROXIED_BY.toString(), tgt.getProxiedBy().getId()); } else { sso.put(SsoSessionAttributeKeys.IS_PROXIED.toString(), Boolean.FALSE); } } sso.put(SsoSessionAttributeKeys.AUTHENTICATED_SERVICES.toString(), tgt.getServices()); activeSessions.add(sso); } return activeSessions; }
@Audit( action = "SERVICE_TICKET", actionResolverName = "GRANT_SERVICE_TICKET_RESOLVER", resourceResolverName = "GRANT_SERVICE_TICKET_RESOURCE_RESOLVER") @Profiled(tag = "GRANT_SERVICE_TICKET", logFailuresSeparately = false) @Transactional(readOnly = false) @Override public String grantServiceTicket( final String ticketGrantingTicketId, final Service service, final Credential... credentials) throws AuthenticationException, TicketException { Assert.notNull(ticketGrantingTicketId, "ticketGrantingticketId cannot be null"); Assert.notNull(service, "service cannot be null"); final TicketGrantingTicket ticketGrantingTicket = this.ticketRegistry.getTicket(ticketGrantingTicketId, TicketGrantingTicket.class); if (ticketGrantingTicket == null) { logger.debug( "TicketGrantingTicket [{}] cannot be found in the ticket registry.", ticketGrantingTicketId); throw new InvalidTicketException(ticketGrantingTicketId); } synchronized (ticketGrantingTicket) { if (ticketGrantingTicket.isExpired()) { this.ticketRegistry.deleteTicket(ticketGrantingTicketId); logger.debug( "TicketGrantingTicket[{}] has expired and is now deleted from the ticket registry.", ticketGrantingTicketId); throw new InvalidTicketException(ticketGrantingTicketId); } } final RegisteredService registeredService = this.servicesManager.findServiceBy(service); verifyRegisteredServiceProperties(registeredService, service); if (!registeredService.isSsoEnabled() && credentials == null && ticketGrantingTicket.getCountOfUses() > 0) { logger.warn("ServiceManagement: Service [{}] is not allowed to use SSO.", service.getId()); throw new UnauthorizedSsoServiceException(); } // CAS-1019 final List<Authentication> authns = ticketGrantingTicket.getChainedAuthentications(); if (authns.size() > 1) { if (!registeredService.isAllowedToProxy()) { final String message = String.format( "ServiceManagement: Proxy attempt by service [%s] (registered service [%s]) is not allowed.", service.getId(), registeredService.toString()); logger.warn(message); throw new UnauthorizedProxyingException(message); } } if (credentials != null) { final Authentication current = this.authenticationManager.authenticate(credentials); final Authentication original = ticketGrantingTicket.getAuthentication(); if (!current.getPrincipal().equals(original.getPrincipal())) { throw new MixedPrincipalException(current, current.getPrincipal(), original.getPrincipal()); } ticketGrantingTicket.getSupplementalAuthentications().add(current); } // Perform security policy check by getting the authentication that satisfies the configured // policy // This throws if no suitable policy is found getAuthenticationSatisfiedByPolicy( ticketGrantingTicket, new ServiceContext(service, registeredService)); final String uniqueTicketIdGenKey = service.getClass().getName(); if (!this.uniqueTicketIdGeneratorsForService.containsKey(uniqueTicketIdGenKey)) { logger.warn( "Cannot create service ticket because the key [{}] for service [{}] is not linked to a ticket id generator", uniqueTicketIdGenKey, service.getId()); throw new UnauthorizedSsoServiceException(); } final UniqueTicketIdGenerator serviceTicketUniqueTicketIdGenerator = this.uniqueTicketIdGeneratorsForService.get(uniqueTicketIdGenKey); final String generatedServiceTicketId = serviceTicketUniqueTicketIdGenerator.getNewTicketId(ServiceTicket.PREFIX); logger.debug( "Generated service ticket id [{}] for ticket granting ticket [{}]", generatedServiceTicketId, ticketGrantingTicket.getId()); final ServiceTicket serviceTicket = ticketGrantingTicket.grantServiceTicket( generatedServiceTicketId, service, this.serviceTicketExpirationPolicy, credentials != null); this.serviceTicketRegistry.addTicket(serviceTicket); if (logger.isInfoEnabled()) { final List<Authentication> authentications = serviceTicket.getGrantingTicket().getChainedAuthentications(); final String formatString = "Granted %s ticket [%s] for service [%s] for user [%s]"; final String type; final String principalId = authentications.get(authentications.size() - 1).getPrincipal().getId(); if (authentications.size() == 1) { type = "service"; } else { type = "proxy"; } logger.info( String.format(formatString, type, serviceTicket.getId(), service.getId(), principalId)); } return serviceTicket.getId(); }
@Audit( action = "SERVICE_TICKET", actionResolverName = "GRANT_SERVICE_TICKET_RESOLVER", resourceResolverName = "GRANT_SERVICE_TICKET_RESOURCE_RESOLVER") @Timed(name = "GRANT_SERVICE_TICKET_TIMER") @Metered(name = "GRANT_SERVICE_TICKET_METER") @Counted(name = "GRANT_SERVICE_TICKET_COUNTER", monotonic = true) @Transactional(readOnly = false) @Override public ServiceTicket grantServiceTicket( final String ticketGrantingTicketId, final Service service, final Credential... credentials) throws AuthenticationException, TicketException { final TicketGrantingTicket ticketGrantingTicket = getTicket(ticketGrantingTicketId, TicketGrantingTicket.class); final RegisteredService registeredService = this.servicesManager.findServiceBy(service); verifyRegisteredServiceProperties(registeredService, service); final Set<Credential> sanitizedCredentials = sanitizeCredentials(credentials); Authentication currentAuthentication = null; if (sanitizedCredentials.size() > 0) { currentAuthentication = this.authenticationManager.authenticate( sanitizedCredentials.toArray(new Credential[] {})); final Authentication original = ticketGrantingTicket.getAuthentication(); if (!currentAuthentication.getPrincipal().equals(original.getPrincipal())) { throw new MixedPrincipalException( currentAuthentication, currentAuthentication.getPrincipal(), original.getPrincipal()); } ticketGrantingTicket.getSupplementalAuthentications().add(currentAuthentication); } if (currentAuthentication == null && !registeredService.getAccessStrategy().isServiceAccessAllowedForSso()) { logger.warn("ServiceManagement: Service [{}] is not allowed to use SSO.", service.getId()); throw new UnauthorizedSsoServiceException(); } final Service proxiedBy = ticketGrantingTicket.getProxiedBy(); if (proxiedBy != null) { logger.debug( "TGT is proxied by [{}]. Locating proxy service in registry...", proxiedBy.getId()); final RegisteredService proxyingService = servicesManager.findServiceBy(proxiedBy); if (proxyingService != null) { logger.debug("Located proxying service [{}] in the service registry", proxyingService); if (!proxyingService.getProxyPolicy().isAllowedToProxy()) { logger.warn( "Found proxying service {}, but it is not authorized to fulfill the proxy attempt made by {}", proxyingService.getId(), service.getId()); throw new UnauthorizedProxyingException( "Proxying is not allowed for registered service " + registeredService.getId()); } } else { logger.warn( "No proxying service found. Proxy attempt by service [{}] (registered service [{}]) is not allowed.", service.getId(), registeredService.getId()); throw new UnauthorizedProxyingException( "Proxying is not allowed for registered service " + registeredService.getId()); } } else { logger.trace("TGT is not proxied by another service"); } // Perform security policy check by getting the authentication that satisfies the configured // policy // This throws if no suitable policy is found getAuthenticationSatisfiedByPolicy( ticketGrantingTicket, new ServiceContext(service, registeredService)); final List<Authentication> authentications = ticketGrantingTicket.getChainedAuthentications(); final Principal principal = authentications.get(authentications.size() - 1).getPrincipal(); final Map<String, Object> principalAttrs = registeredService.getAttributeReleasePolicy().getAttributes(principal); if (!registeredService .getAccessStrategy() .doPrincipalAttributesAllowServiceAccess(principalAttrs)) { logger.warn( "ServiceManagement: Cannot grant service ticket because Service [{}] is not authorized for use by [{}].", service.getId(), principal); throw new UnauthorizedServiceForPrincipalException(); } final String uniqueTicketIdGenKey = service.getClass().getName(); logger.debug("Looking up service ticket id generator for [{}]", uniqueTicketIdGenKey); UniqueTicketIdGenerator serviceTicketUniqueTicketIdGenerator = this.uniqueTicketIdGeneratorsForService.get(uniqueTicketIdGenKey); if (serviceTicketUniqueTicketIdGenerator == null) { serviceTicketUniqueTicketIdGenerator = this.defaultServiceTicketIdGenerator; logger.debug( "Service ticket id generator not found for [{}]. Using the default generator...", uniqueTicketIdGenKey); } final String ticketPrefix = authentications.size() == 1 ? ServiceTicket.PREFIX : ServiceTicket.PROXY_TICKET_PREFIX; final String ticketId = serviceTicketUniqueTicketIdGenerator.getNewTicketId(ticketPrefix); final ServiceTicket serviceTicket = ticketGrantingTicket.grantServiceTicket( ticketId, service, this.serviceTicketExpirationPolicy, currentAuthentication != null); this.serviceTicketRegistry.addTicket(serviceTicket); logger.info( "Granted ticket [{}] for service [{}] for user [{}]", serviceTicket.getId(), service.getId(), principal.getId()); return serviceTicket; }
@Override protected ModelAndView handleRequestInternal( final HttpServletRequest request, final HttpServletResponse response) throws Exception { final HttpSession session = request.getSession(); // get cas login service ticket final String serviceTicketId = request.getParameter(OAuthConstants.TICKET); LOGGER.debug("{} : {}", OAuthConstants.TICKET, serviceTicketId); // first time this url is requested the login ticket will be a query parameter if (serviceTicketId != null) { // create the login ticket granting ticket final ServiceTicket serviceTicket = (ServiceTicket) ticketRegistry.getTicket(serviceTicketId); // login service ticket should be valid if (serviceTicket == null || serviceTicket.isExpired()) { LOGGER.error("Service Ticket expired : {}", serviceTicketId); return OAuthUtils.writeTextError( response, OAuthConstants.INVALID_GRANT, HttpStatus.SC_BAD_REQUEST); } final TicketGrantingTicket ticketGrantingTicket = serviceTicket.getGrantingTicket(); // remove login service ticket ticketRegistry.deleteTicket(serviceTicket.getId()); // store the login tgt id in the user's session, used to create service tickets for validation // and // oauth credentials later in the flow. session.setAttribute(OAuthConstants.OAUTH20_LOGIN_TICKET_ID, ticketGrantingTicket.getId()); // redirect back to self, clears the service ticket from the url, allows the url to be // requested multiple // times w/o error return OAuthUtils.redirectTo(request.getRequestURL().toString()); } // get cas login service ticket from the session String ticketGrantingTicketId = (String) session.getAttribute(OAuthConstants.OAUTH20_LOGIN_TICKET_ID); LOGGER.debug("{} : {}", OAuthConstants.TICKET, ticketGrantingTicketId); if (StringUtils.isBlank(ticketGrantingTicketId)) { LOGGER.error("Missing Ticket Granting Ticket"); return OAuthUtils.writeTextError( response, OAuthConstants.INVALID_GRANT, HttpStatus.SC_BAD_REQUEST); } // verify the login ticket granting ticket is still valid TicketGrantingTicket ticketGrantingTicket = (TicketGrantingTicket) ticketRegistry.getTicket(ticketGrantingTicketId); if (ticketGrantingTicket == null || ticketGrantingTicket.isExpired()) { LOGGER.error("Ticket Granting Ticket expired : {}", ticketGrantingTicketId); return OAuthUtils.writeTextError( response, OAuthConstants.INVALID_GRANT, HttpStatus.SC_BAD_REQUEST); } String callbackUrl = request .getRequestURL() .toString() .replace( "/" + OAuthConstants.CALLBACK_AUTHORIZE_URL, "/" + OAuthConstants.CALLBACK_AUTHORIZE_ACTION_URL); LOGGER.debug("{} : {}", OAuthConstants.CALLBACK_AUTHORIZE_ACTION_URL, callbackUrl); String allowCallbackUrl = OAuthUtils.addParameter( callbackUrl, OAuthConstants.OAUTH20_APPROVAL_PROMPT_ACTION, OAuthConstants.OAUTH20_APPROVAL_PROMPT_ACTION_ALLOW); final Map<String, Object> model = new HashMap<>(); model.put("callbackUrl", callbackUrl); final Boolean bypassApprovalPrompt = (Boolean) session.getAttribute(OAuthConstants.BYPASS_APPROVAL_PROMPT); LOGGER.debug("bypassApprovalPrompt : {}", bypassApprovalPrompt); if (bypassApprovalPrompt != null && bypassApprovalPrompt) { return OAuthUtils.redirectTo(allowCallbackUrl); } final String clientId = (String) session.getAttribute(OAuthConstants.OAUTH20_CLIENT_ID); LOGGER.debug("{} : {}", OAuthConstants.CLIENT_ID, clientId); final Principal loginPrincipal = ticketGrantingTicket.getAuthentication().getPrincipal(); final String approvalPrompt = (String) session.getAttribute(OAuthConstants.OAUTH20_APPROVAL_PROMPT); LOGGER.debug("approvalPrompt : {}", approvalPrompt); if (StringUtils.isBlank(approvalPrompt) || !approvalPrompt.equalsIgnoreCase(OAuthConstants.APPROVAL_PROMPT_FORCE)) { final TicketGrantingTicket refreshToken = OAuthTokenUtils.getRefreshToken(centralAuthenticationService, clientId, loginPrincipal); if (refreshToken != null) { return OAuthUtils.redirectTo(allowCallbackUrl); } } // retrieve service name from session final String serviceName = (String) session.getAttribute(OAuthConstants.OAUTH20_SERVICE_NAME); LOGGER.debug("serviceName : {}", serviceName); model.put("serviceName", serviceName); return new ModelAndView(OAuthConstants.CONFIRM_VIEW, model); }