package org.pac4j.cas.credentials.authenticator;

import org.pac4j.cas.config.CasConfiguration;
import org.pac4j.core.util.HttpUtils;
import org.pac4j.cas.profile.CasRestProfile;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.credentials.UsernamePasswordCredentials;
import org.pac4j.core.credentials.authenticator.Authenticator;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableWebObject;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * This is a specific Authenticator to deal with the CAS REST API.
 *
 * @author Misagh Moayyed
 * @since 1.8.0
 */
public class CasRestAuthenticator extends InitializableWebObject implements Authenticator<UsernamePasswordCredentials> {

    private CasConfiguration configuration;

    public CasRestAuthenticator() {}

    public CasRestAuthenticator(final CasConfiguration configuration) {
        this.configuration = configuration;
    }

    @Override
    protected void internalInit(final WebContext context) {
        CommonHelper.assertNotNull("configuration", this.configuration);
        configuration.init(context);
    }

    @Override
    public void validate(final UsernamePasswordCredentials credentials, final WebContext context) throws HttpAction {
        init(context);

        if (credentials == null || credentials.getPassword() == null || credentials.getUsername() == null) {
            throw new TechnicalException("Credentials are required");
        }
        final String ticketGrantingTicketId = requestTicketGrantingTicket(credentials.getUsername(), credentials.getPassword(), context);
        final CasRestProfile profile = new CasRestProfile(ticketGrantingTicketId, credentials.getUsername());
        credentials.setUserProfile(profile);
    }

    private String requestTicketGrantingTicket(final String username, final String password, final WebContext context) {
        HttpURLConnection connection = null;
        try {
            connection = HttpUtils.openPostConnection(new URL(this.configuration.computeFinalRestUrl(context)));
            final String payload = HttpUtils.encodeQueryParam(Pac4jConstants.USERNAME, username)
                    + "&" + HttpUtils.encodeQueryParam(Pac4jConstants.PASSWORD, password);

            final BufferedWriter out = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), HttpConstants.UTF8_ENCODING));
            out.write(payload);
            out.close();

            final String locationHeader = connection.getHeaderField("location");
            final int responseCode = connection.getResponseCode();
            if (locationHeader != null && responseCode == HttpConstants.CREATED) {
                return locationHeader.substring(locationHeader.lastIndexOf("/") + 1);
            }

            throw new TechnicalException("Ticket granting ticket request failed: " + locationHeader + " " + responseCode +
                    HttpUtils.buildHttpErrorMessage(connection));
        } catch (final IOException e) {
            throw new TechnicalException(e);
        } finally {
            HttpUtils.closeConnection(connection);
        }
    }

    public CasConfiguration getConfiguration() {
        return configuration;
    }

    public void setConfiguration(final CasConfiguration configuration) {
        this.configuration = configuration;
    }
}

@@ -54,83 +54,196 @@
 ort 
-org.pac4j.cas.config.CasConfiguration;%0Aimport org.pac4j.core.util.HttpUtils
+java.io.BufferedWriter;%0Aimport java.io.IOException;%0Aimport java.io.OutputStreamWriter;%0Aimport java.net.HttpURLConnection;%0Aimport java.net.URL;%0A%0Aimport org.pac4j.cas.config.CasConfiguration
 ;%0Aim
@@ -444,104 +444,8 @@
 ore.
-exception.HttpAction;%0Aimport org.pac4j.core.exception.TechnicalException;%0Aimport org.pac4j.core.
 cred
@@ -542,16 +542,112 @@
 nticator
+;%0Aimport org.pac4j.core.exception.HttpAction;%0Aimport org.pac4j.core.exception.TechnicalException
 ;%0Aimport
@@ -677,24 +677,62 @@
 mmonHelper;%0A
+import org.pac4j.core.util.HttpUtils;%0A
 import org.p
@@ -774,157 +774,63 @@
 ct;%0A
-%0A
 import 
-java.io.BufferedWriter;%0Aimport java.io.IOException;%0Aimport java.io.OutputStreamWriter;%0Aimport java.net.HttpURLConnection;%0Aimport java.net.URL
+org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory
 ;%0A%0A/
@@ -1070,16 +1070,108 @@
 als%3E %7B%0A%0A
+%09private final static Logger logger = LoggerFactory.getLogger(CasRestAuthenticator.class);%0A%0A
     priv
@@ -2046,47 +2046,95 @@
 t);%0A
-        final CasRestProfile profile = 
+%09%09if (CommonHelper.isNotBlank(ticketGrantingTicketId)) %7B%0A%09%09%09credentials.setUserProfile(
 new 
@@ -2171,17 +2171,22 @@
 icketId,
- 
+%0A%09%09%09%09%09
 credenti
@@ -2207,54 +2207,14 @@
 e())
-;%0A        credentials.setUserProfile(profile);
+);%0A%09%09%7D
 %0A   
@@ -3235,48 +3235,23 @@
  %7D%0A%0A
-            throw new TechnicalException
+%09%09%09logger.debug
 (%22Ti
@@ -3311,17 +3311,22 @@
 er + %22 %22
- 
+%0A%09%09%09%09%09
 + respon
@@ -3399,16 +3399,33 @@
 ction));
+%0A%0A%09%09%09return null;
 %0A       

return null profile when CAS authentication failed (#953)