/* * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you 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 the following location: * * 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.openiot.security.oauth; import java.security.Principal; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.jasig.cas.CentralAuthenticationService; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; import org.jasig.cas.services.RegisteredService; import org.jasig.cas.services.ServicesManager; import org.jasig.cas.ticket.TicketException; import org.restlet.data.Form; import org.restlet.data.MediaType; import org.restlet.data.Reference; import org.restlet.data.Request; import org.restlet.data.Status; import org.restlet.resource.Representation; import org.restlet.resource.Resource; import org.restlet.resource.ResourceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.web.bind.support.WebRequestDataBinder; import org.springframework.web.context.request.WebRequest; /** * Handles the creation of Ticket Granting Tickets. * * @author Scott Battaglia * @author Mehdi Riahi * @version $Revision$ $Date$ * @since 3.3 * */ public class TicketResource extends Resource { private static final Logger log = LoggerFactory.getLogger(TicketResource.class); @Autowired private CentralAuthenticationService centralAuthenticationService; @Autowired private ServicesManager servicesManager; public final boolean allowGet() { return false; } public final boolean allowPost() { return true; } public final void acceptRepresentation(final Representation entity) throws ResourceException { if (log.isDebugEnabled()) { log.debug("Obtaining credentials..."); log.debug(getRequest().getEntityAsForm().toString()); } final RestTGTRequestCredentials credentials = obtainCredentials(); final Collection<RegisteredService> services = servicesManager.getAllServices(); RegisteredService service = null; for (final RegisteredService aService : services) { if (StringUtils.equals(aService.getName(), credentials.getClientId())) { service = aService; break; } } if (service == null) { log.warn("Request for TGT from unknown client: {}", credentials.getClientId()); getResponse().setStatus(Status.CLIENT_ERROR_UNAUTHORIZED, "Request for TGT from unknown client"); } else if (!credentials.getSecret().equals(service.getDescription())) { log.warn("Client secret [{}] deosn't match for client [{}]", credentials.getSecret(), credentials.getClientId()); getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Client secret doesn't match"); } else { try { UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials(); usernamePasswordCredentials.setUsername(credentials.getUsername()); usernamePasswordCredentials.setPassword(credentials.getPassword()); final String ticketGrantingTicketId = this.centralAuthenticationService.createTicketGrantingTicket(usernamePasswordCredentials); getResponse().setStatus(determineStatus()); final Reference ticket_ref = getRequest().getResourceRef().addSegment(ticketGrantingTicketId); getResponse().setLocationRef(ticket_ref); getResponse() .setEntity( "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><html><head><title>" + getResponse().getStatus().getCode() + " " + getResponse().getStatus().getDescription() + "</title></head><body><h1>TGT Created</h1><form action=\"" + ticket_ref + "\" method=\"POST\">Service:<input type=\"text\" name=\"service\" value=\"\"><br><input type=\"submit\" value=\"Submit\"></form></body></html>", MediaType.TEXT_HTML); } catch (final TicketException e) { log.error(e.getMessage(), e); getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, e.getMessage()); } } } /** * Template method for determining which status to return on a successful ticket creation. This * method exists for compatibility reasons with bad clients (i.e. Flash) that can't process 201 * with a Location header. * * @return the status to return. */ protected Status determineStatus() { return Status.SUCCESS_CREATED; } protected RestTGTRequestCredentials obtainCredentials() { final RestTGTRequestCredentials c = new RestTGTRequestCredentials(); final WebRequestDataBinder binder = new WebRequestDataBinder(c); final RestletWebRequest webRequest = new RestletWebRequest(getRequest()); if (log.isDebugEnabled()) { log.debug(getRequest().getEntityAsForm().toString()); log.debug("Username from RestletWebRequest: " + webRequest.getParameter("username")); } binder.bind(webRequest); return c; } protected class RestletWebRequest implements WebRequest { private final Form form; private final Request request; public RestletWebRequest(final Request request) { this.form = getRequest().getEntityAsForm(); this.request = request; } public boolean checkNotModified(String s) { return false; } public boolean checkNotModified(long lastModifiedTimestamp) { return false; } public String getContextPath() { return this.request.getResourceRef().getPath(); } public String getDescription(boolean includeClientInfo) { return null; } public Locale getLocale() { return LocaleContextHolder.getLocale(); } public String getParameter(String paramName) { return this.form.getFirstValue(paramName); } public Map<String, String[]> getParameterMap() { final Map<String, String[]> conversion = new HashMap<String, String[]>(); for (final Map.Entry<String, String> entry : this.form.getValuesMap().entrySet()) { conversion.put(entry.getKey(), new String[] { entry.getValue() }); } return conversion; } public String[] getParameterValues(String paramName) { return this.form.getValuesArray(paramName); } public String getRemoteUser() { return null; } public Principal getUserPrincipal() { return null; } public boolean isSecure() { return this.request.isConfidential(); } public boolean isUserInRole(String role) { return false; } public Object getAttribute(String name, int scope) { return null; } public String[] getAttributeNames(int scope) { return null; } public String getSessionId() { return null; } public Object getSessionMutex() { return null; } public void registerDestructionCallback(String name, Runnable callback, int scope) { // nothing to do } public void removeAttribute(String name, int scope) { // nothing to do } public void setAttribute(String name, Object value, int scope) { // nothing to do } public String getHeader(final String s) { return null; } public String[] getHeaderValues(String s) { return new String[0]; } public Iterator<String> getHeaderNames() { return null; } public Iterator<String> getParameterNames() { return null; } public Object resolveReference(String s) { return null; } } }