/*
 * Copyright 2011 the original author or authors.
 *
 * 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.springframework.security.samples.cas

import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.methods.GetMethod
import org.jasig.cas.client.jaas.CasLoginModule;
import org.jasig.cas.client.proxy.Cas20ProxyRetriever
import org.springframework.security.samples.cas.pages.*

import spock.lang.*


/**
 * Tests authenticating to the CAS Sample application using Proxy Tickets. Geb is used to authenticate the {@link JettyCasService}
 * to the CAS Server in order to obtain the Ticket Granting Ticket. Afterwards HttpClient is used for accessing the CAS Sample application
 * using Proxy Tickets obtained using the Proxy Granting Ticket.
 *
 * @author Rob Winch
 */
@Stepwise
class CasSampleProxyTests extends AbstractCasTests {
	HttpClient client = new HttpClient()
	@Shared String casServerUrl = LoginPage.url.replaceFirst('/login','')
	@Shared JettyCasService service = new JettyCasService().init(casServerUrl)
	@Shared Cas20ProxyRetriever retriever = new Cas20ProxyRetriever(casServerUrl,'UTF-8')
	@Shared String pt

	def cleanupSpec() {
		service.stop()
	}

	def 'access secure page succeeds with ROLE_USER'() {
		setup: 'Obtain a pgt for a user with ROLE_USER'
		driver.get LoginPage.url+"?service="+service.serviceUrl()
		at LoginPage
		login 'scott'
		when: 'User with ROLE_USER accesses the secure page'
		def content = getSecured(getBaseUrl()+SecurePage.url).responseBodyAsString
		then: 'The secure page is returned'
		content.contains('<h1>Secure Page</h1>')
	}

	def 'access proxy ticket sample succeeds with ROLE_USER'() {
		when: 'a proxy ticket is used to create another proxy ticket'
		def content = getSecured(getBaseUrl()+ProxyTicketSamplePage.url).responseBodyAsString
		then: 'The proxy ticket sample page is returned'
		content.contains('<h1>Secure Page using a Proxy Ticket</h1>')
	}

	def 'access extremely secure page with ROLE_USER is denied'() {
		when: 'User with ROLE_USER accesses the extremely secure page'
		GetMethod method = getSecured(getBaseUrl()+ExtremelySecurePage.url)
		then: 'access is denied'
		assert method.responseBodyAsString =~ /(?i)403.*?Denied/
		assert 403 == method.statusCode
	}

	def 'access secure page with ROLE_SUPERVISOR succeeds'() {
		setup: 'Obtain pgt for user with ROLE_SUPERVISOR'
		to LocalLogoutPage
		casServerLogout.click()
		driver.get(LoginPage.url+"?service="+service.serviceUrl())
		at LoginPage
		login 'rod'
		when: 'User with ROLE_SUPERVISOR accesses the secure page'
		def content = getSecured(getBaseUrl()+ExtremelySecurePage.url).responseBodyAsString
		then: 'The secure page is returned'
		content.contains('<h1>VERY Secure Page</h1>')
	}

	def 'access extremely secure page with ROLE_SUPERVISOR reusing pt succeeds (stateless mode works)'() {
		when: 'User with ROLE_SUPERVISOR accesses extremely secure page with used pt'
		def content = getSecured(getBaseUrl()+ExtremelySecurePage.url,pt).responseBodyAsString
		then: 'The extremely secure page is returned'
		content.contains('<h1>VERY Secure Page</h1>')
	}

	def 'access secure page with invalid proxy ticket fails'() {
		when: 'Invalid ticket is used to access secure page'
		GetMethod method = getSecured(getBaseUrl()+SecurePage.url,'invalidticket')
		then: 'Authentication fails'
		method.statusCode == 401
	}

	/**
	 * Gets the result of calling a url with a proxy ticket
	 * @param targetUrl the absolute url to attempt to access
	 * @param pt the proxy ticket to use. Defaults to {@link #getPt(String)} with targetUrl specified for the targetUrl.
	 * @return the GetMethod after calling a url with a specified proxy ticket
	 */
	GetMethod getSecured(String targetUrl,String pt=getPt(targetUrl)) {
		assert pt != null
		GetMethod method = new GetMethod(targetUrl+"?ticket="+pt)
		int status = client.executeMethod(method)
		method
	}

	/**
	 * Obtains a proxy ticket using the pgt from the {@link #service}.
	 * @param targetService the targetService that the proxy ticket will be valid for
	 * @return a proxy ticket for targetService
	 */
	String getPt(String targetService) {
		assert service.pgt != null
		pt = retriever.getProxyTicketIdFor(service.pgt, targetService)
		pt
	}
}