/*
 * Copyright (c) eHealth
 */
package be.ehealth.technicalconnector.service.sts.impl;

import be.ehealth.technicalconnector.beid.BeIDFactory;
import be.ehealth.technicalconnector.service.sts.STSService;
import be.ehealth.technicalconnector.service.sts.domain.SAMLAttribute;
import be.ehealth.technicalconnector.service.sts.domain.SAMLAttributeDesignator;
import be.ehealth.technicalconnector.service.sts.security.Credential;
import be.ehealth.technicalconnector.service.sts.security.impl.BeIDCredential;
import be.ehealth.technicalconnector.service.sts.security.impl.KeyStoreCredential;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.ConnectorXmlUtils;
import be.fedict.commons.eid.jca.BeIDProvider;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.SessionRule;
import be.fgov.ehealth.technicalconnector.tests.utils.AssumeTools;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.Base64;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.w3c.dom.Element;

import java.security.Security;
import java.util.ArrayList;
import java.util.List;


/**
 * BaseTest regrouping all the function needed for the STSService test
 * 
 * @author EHP
 */
public abstract class STSServiceBaseTest {

    private static final String XMLNS_SAML = "urn:oasis:names:tc:SAML:1.0:assertion";

    @ClassRule
    public static SessionRule rule = SessionRule.withInactiveSession().build();
    private STSService service;

    @Test
    public void renewTokenBasedOnEid() throws Exception {
        AssumeTools.isEIDEnabled();
        BeIDCredential headerCred = BeIDCredential.getInstance("session", BeIDCredential.EID_AUTH_ALIAS);
        String keystoreloc = rule.getSessionProperty("test.keystore.location");
        String alias = rule.getSessionProperty("test.keystore.alias");
        String pwd = rule.getSessionProperty("test.keystore.password");
        String pkpwd = rule.getSessionProperty("test.keystore.privatekeypassword");

        KeyStoreCredential bodyCred = new KeyStoreCredential(keystoreloc, pwd, alias, pkpwd);
        String hok = new String(Base64.encode(bodyCred.getCertificate()
                                                      .getEncoded()));
        String persistToken = ConnectorIOUtils.convertStreamToString(ConnectorIOUtils.getResourceAsStream("/examples/sas/renew.eid.sas"));
        persistToken = StringUtils.replace(persistToken, "${user.inss}",  BeIDFactory.getBeIDInfo("test",false)
                                                                                 .getIdentity()
                                                                                 .getNationalNumber());
        persistToken = StringUtils.replace(persistToken, "${hok}", hok);

        Element samlToken = ConnectorXmlUtils.toElement(persistToken.getBytes());

        int expected = samlToken.getElementsByTagNameNS(XMLNS_SAML, "Attribute")
                                .getLength();
        for (int i = 0; i < 5; i++) {
            samlToken = service.renewToken(headerCred, bodyCred, samlToken, 24);
        }

        Assert.assertEquals(expected, samlToken.getElementsByTagNameNS(XMLNS_SAML, "Attribute")
                                        .getLength());

    }

    @Test
    public void issueEid() throws Exception {
        AssumeTools.isEIDEnabled();
        BeIDCredential headerCred = BeIDCredential.getInstance("session", BeIDCredential.EID_AUTH_ALIAS);

        String keystoreloc = rule.getSessionProperty("test.keystore.location");
        String alias = rule.getSessionProperty("test.keystore.alias");
        String pwd = rule.getSessionProperty("test.keystore.password");
        String pkpwd = rule.getSessionProperty("test.keystore.privatekeypassword");
        KeyStoreCredential bodyCred = new KeyStoreCredential(keystoreloc, pwd, alias, pkpwd);

        String inss = BeIDFactory.getBeIDInfo("session",false)
                              .getIdentity()
                              .getNationalNumber();

        List<SAMLAttributeDesignator> designators = new ArrayList<SAMLAttributeDesignator>();
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace"));

        // create the list of SAML Attributes
        List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
        attributes.add(new SAMLAttribute("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace", inss));
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace", inss));

        service.getToken(headerCred, bodyCred, attributes, designators, AbstractSTSService.HOK_METHOD, 24);
    }

    @Test
    public void issueEidOnly() throws Exception {
        AssumeTools.isEIDEnabled();
        Credential headerCred = BeIDCredential.getInstance("session", BeIDCredential.EID_AUTH_ALIAS);
        Credential bodyCred = headerCred;

        String inss =  BeIDFactory.getBeIDInfo("session",false)
                              .getIdentity()
                              .getNationalNumber();

        List<SAMLAttributeDesignator> designators = new ArrayList<SAMLAttributeDesignator>();
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace"));

        // create the list of SAML Attributes
        List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
        attributes.add(new SAMLAttribute("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace", inss));
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace", inss));

        service.getToken(headerCred, bodyCred, attributes, designators, AbstractSTSService.HOK_METHOD, 24);
    }

    @Test
    public void issueSVEid() throws Exception {
        AssumeTools.isEIDEnabled();
        String keystoreloc = rule.getSessionProperty("test.session.sv.keystore.location");
        String alias = rule.getSessionProperty("test.session.sv.keystore.alias");
        String pwd = rule.getSessionProperty("test.session.sv.keystore.password");
        String pkpwd = rule.getSessionProperty("test.session.sv.keystore.privatekeypassword");
        Credential cred = new KeyStoreCredential(keystoreloc, pwd, alias, pkpwd);

        String inss = rule.getSessionProperty("test.session.user");

        List<SAMLAttributeDesignator> designators = new ArrayList<SAMLAttributeDesignator>();
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:person:ssin:ehealth:1.0:doctor:nihii11", "urn:be:fgov:certified-namespace"));
        // create the list of SAML Attributes
        List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
        attributes.add(new SAMLAttribute("urn:be:fgov:person:ssin", "urn:be:fgov:identification-namespace", inss));
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:certificateholder:person:ssin", "urn:be:fgov:identification-namespace", inss));
        service.getToken(cred, cred, attributes, designators, "test", "urn:be:fgov:ehealth:connector:gui", inss, AbstractSTSService.SV_METHOD, 24);


    }

    @Test
    public void issueTokenForMandator() throws Exception {
        String keystoreloc = rule.getSessionProperty("test.session.sv.keystore.location");
        String alias = rule.getSessionProperty("test.session.sv.keystore.alias");
        String pwd = rule.getSessionProperty("test.session.sv.keystore.password");
        String pkpwd = rule.getSessionProperty("test.session.sv.keystore.privatekeypassword");
        Credential headerCred = new KeyStoreCredential(keystoreloc, pwd, alias, pkpwd);

        Credential bodyCred = headerCred;

        String cbe = "0809394427";

        List<SAMLAttributeDesignator> designators = new ArrayList<SAMLAttributeDesignator>();
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:certificateholder:enterprise:cbe-number", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:kbo-bce:organization:cbe-number", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:servicename:external", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:kbo-bce:organization:cbe-number:ehealth:1.0:recognisedmandatary:boolean", "urn:be:fgov:certified-namespace:ehealth"));

        // create the list of SAML Attributes
        List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:certificateholder:enterprise:cbe-number", "urn:be:fgov:identification-namespace", cbe));
        attributes.add(new SAMLAttribute("urn:be:fgov:kbo-bce:organization:cbe-number", "urn:be:fgov:identification-namespace", cbe));
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:servicename:external", "urn:be:fgov:identification-namespace", "insurability"));

        service.getToken(headerCred, bodyCred, attributes, designators, AbstractSTSService.HOK_METHOD, 24);
    }

    @Test
    public void renewToken() throws Exception {
        String keystoreloc = rule.getSessionProperty("test.session.sv.keystore.location");
        String alias = rule.getSessionProperty("test.session.sv.keystore.alias");
        String pwd = rule.getSessionProperty("test.session.sv.keystore.password");
        String pkpwd = rule.getSessionProperty("test.session.sv.keystore.privatekeypassword");
        Credential headerCred = new KeyStoreCredential(keystoreloc, pwd, alias, pkpwd);

        Credential bodyCred = headerCred;

        String cbe = "0809394427";

        List<SAMLAttributeDesignator> designators = new ArrayList<SAMLAttributeDesignator>();
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:ehealth:1.0:certificateholder:enterprise:cbe-number", "urn:be:fgov:identification-namespace"));
        designators.add(new SAMLAttributeDesignator("urn:be:fgov:kbo-bce:organization:cbe-number", "urn:be:fgov:identification-namespace"));

        // create the list of SAML Attributes
        List<SAMLAttribute> attributes = new ArrayList<SAMLAttribute>();
        attributes.add(new SAMLAttribute("urn:be:fgov:ehealth:1.0:certificateholder:enterprise:cbe-number", "urn:be:fgov:identification-namespace", cbe));
        attributes.add(new SAMLAttribute("urn:be:fgov:kbo-bce:organization:cbe-number", "urn:be:fgov:identification-namespace", cbe));

        Element token = service.getToken(headerCred, bodyCred, attributes, designators, AbstractSTSService.HOK_METHOD, 24);
        Assert.assertEquals(2, token.getElementsByTagNameNS("urn:oasis:names:tc:SAML:1.0:assertion", "Attribute")
                                    .getLength());
        for (int i = 0; i < 5; i++) {
            token = service.renewToken(headerCred, bodyCred, token, 24);
        }
        Assert.assertEquals(2, token.getElementsByTagNameNS("urn:oasis:names:tc:SAML:1.0:assertion", "Attribute")
                                    .getLength());

    }


    /**
     * @param service the service to set
     */
    public void setService(STSService service) {
        this.service = service;
    }
}