package pl.cyfronet.kdm.guacamole.auth.openid;

import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
import org.openid4java.OpenIDException;
import org.openid4java.association.AssociationException;
import org.openid4java.association.AssociationSessionType;
import org.openid4java.consumer.*;
import org.openid4java.discovery.DiscoveryException;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.MessageException;
import org.openid4java.message.ParameterList;
import org.openid4java.message.ax.FetchRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.cyfronet.kdm.guacamole.auth.openid.form.OpenIDField;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;

public class OpenIDAuthenticationService {

    private static final Logger logger = LoggerFactory.getLogger(OpenIDAuthenticationService.class);
    public static final String FIELD_EMAIL_URI = "http://schema.openid.net/contact/email";
    public static final String FIELD_EMAIL_NAME = "email";


    private static ConsumerManager consumerManager;
    private final String openIdEndpoint;
    private final String returnToUrl;
    private final String realm;

    {
        logger.debug("Creating new ConsumerManagera");
        consumerManager = new ConsumerManager();
        consumerManager.setAssociations(new InMemoryConsumerAssociationStore());
        consumerManager.setNonceVerifier(new InMemoryNonceVerifier(5000));
        consumerManager.setMinAssocSessEnc(AssociationSessionType.DH_SHA256);
    }


    public OpenIDAuthenticationService(HttpServletRequest request) throws GuacamoleException {

        //initialize parameters from properties
        Environment environment = new LocalEnvironment();

        openIdEndpoint = environment.getRequiredProperty(OpenIDAuthenticationProperties.OPENID_ENDPOINT);
        logger.debug("Setting openIdEndpoint to: {}", openIdEndpoint);
        returnToUrl = environment.getRequiredProperty(OpenIDAuthenticationProperties.OPENID_RETURNTOURL);
        logger.debug("Setting returnToUrl to: {}", returnToUrl);
        realm = environment.getRequiredProperty(OpenIDAuthenticationProperties.OPENID_REALM);
        logger.debug("Setting realm to: {}", realm);
    }

    public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException {
        logger.debug("Service authenticateUser()");
        //put openid code here, check for proper request if it's invalid throw exception

        HttpServletRequest httpServletRequest = credentials.getRequest();

        logger.debug("queryURL: {}", httpServletRequest.getRequestURI());
        logger.debug("queryString: {}", httpServletRequest.getQueryString());
        for (Enumeration e = httpServletRequest.getAttributeNames(); e.hasMoreElements(); ) {
            logger.debug("attribute: {}", e.nextElement());
        }
        logger.debug("parameterCount: {}", httpServletRequest.getParameterMap().keySet().size());

        for (Object keyObj : httpServletRequest.getParameterMap().keySet()) {
            String key = (String) keyObj;
            logger.debug("key: {}", key);
        }
        if (httpServletRequest.getParameter("openid.op_endpoint") != null) {
            logger.debug("authenticateUser(): handle reposnse");
            try {
                //handle incoming openid response

                ParameterList response = new ParameterList(httpServletRequest.getParameterMap());
                DiscoveryInformation discovered = (DiscoveryInformation) httpServletRequest.getSession().getAttribute("openid-disc");

                StringBuffer receivingURL = new StringBuffer(returnToUrl);
                String queryString = httpServletRequest.getQueryString();
                if (queryString != null && queryString.length() > 0)
                    receivingURL.append("?").append(httpServletRequest.getQueryString());

                VerificationResult verification = consumerManager.verify(receivingURL.toString(), response, discovered);

                Identifier verified = verification.getVerifiedId();
                logger.debug("finished with verification");
                if (verified != null) {
                    //success!
                    logger.debug("success");
                    logger.debug(verified.getIdentifier());
                    return null;
                }
            } catch (OpenIDException e) {
                e.printStackTrace();
            }

        } else {
            //place a request for new authentication action
            logger.debug("authenticateUser(): place auth request");
            List discoveries = null;
            try {
                discoveries = consumerManager.discover(openIdEndpoint);
                DiscoveryInformation discovered = consumerManager.associate(discoveries);

                httpServletRequest.getSession().setAttribute("openid-disc", discovered);

                FetchRequest fetch = FetchRequest.createFetchRequest();
                fetch.addAttribute(FIELD_EMAIL_NAME, FIELD_EMAIL_URI, true);

                AuthRequest authReq = consumerManager.authenticate(discovered, returnToUrl);
                authReq.setRealm(realm);
                authReq.addExtension(fetch);

                String destinationUrl = authReq.getDestinationUrl(true);
                logger.debug("destinationURL: {}", destinationUrl);
                throw new GuacamoleInvalidCredentialsException("Invalid login",
                        new CredentialsInfo(Arrays.asList(new Field[]{
                                new OpenIDField(
                                        destinationUrl
                                )
                        }))
                );
            } catch (DiscoveryException e) {
                e.printStackTrace();
            } catch (ConsumerException e) {
                e.printStackTrace();
            } catch (MessageException e) {
                e.printStackTrace();
            }

        }
//        throw new GuacamoleInvalidCredentialsException("Invalid login",
//                new CredentialsInfo(Arrays.asList(new Field[]{
//                        new OpenIDField(
//                                "asd"
//                        )
//                }))
//        );
        return null;
    }

}

@@ -1447,158 +1447,8 @@
 s);%0A
-    public static final String FIELD_EMAIL_URI = %22http://schema.openid.net/contact/email%22;%0A    public static final String FIELD_EMAIL_NAME = %22email%22;%0A
 %0A%0A  
@@ -3625,19 +3625,16 @@
 nid.
-op_endpoint
+identity
 %22) !
@@ -5347,158 +5347,8 @@
 );%0A%0A
-                FetchRequest fetch = FetchRequest.createFetchRequest();%0A                fetch.addAttribute(FIELD_EMAIL_NAME, FIELD_EMAIL_URI, true);%0A%0A
     
@@ -5480,53 +5480,8 @@
 lm);
-%0A                authReq.addExtension(fetch);
 %0A%0A  
@@ -5980,539 +5980,90 @@
 ch (
-DiscoveryException e) %7B%0A                e.printStackTrace();%0A            %7D catch (ConsumerException e) %7B%0A                e.printStackTrace();%0A            %7D catch (MessageException e) %7B%0A                e.printStackTrace();%0A            %7D%0A%0A        %7D%0A//        throw new GuacamoleInvalidCredentialsException(%22Invalid login%22,%0A//                new CredentialsInfo(Arrays.asList(new Field%5B%5D%7B%0A//                        new OpenIDField(%0A//                                %22asd%22%0A//                        )%0A//                %7D))%0A//        );
+OpenIDException e) %7B%0A                e.printStackTrace();%0A            %7D%0A%0A        %7D
 %0A   

Remove email request.