package org.apereo.cas.support.saml.web.idp.profile.builders;

import org.apereo.cas.configuration.CasConfigurationProperties;
import org.apereo.cas.support.saml.OpenSamlConfigBean;
import org.apereo.cas.support.saml.SamlException;
import org.apereo.cas.support.saml.SamlIdPUtils;
import org.apereo.cas.support.saml.services.SamlRegisteredService;
import org.apereo.cas.support.saml.services.idp.metadata.SamlRegisteredServiceServiceProviderMetadataFacade;
import org.apereo.cas.support.saml.util.AbstractSaml20ObjectBuilder;
import org.apereo.cas.util.DateTimeUtils;
import org.jasig.cas.client.validation.Assertion;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.AuthnStatement;
import org.opensaml.saml.saml2.core.SubjectLocality;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.SecureRandom;
import java.time.ZonedDateTime;

/**
 * This is {@link SamlProfileSamlAuthNStatementBuilder}.
 *
 * @author Misagh Moayyed
 * @since 5.0.0
 */
public class SamlProfileSamlAuthNStatementBuilder extends AbstractSaml20ObjectBuilder implements SamlProfileObjectBuilder<AuthnStatement> {

    private static final long serialVersionUID = 8761566449790497226L;

    @Autowired
    private CasConfigurationProperties casProperties;

    private final AuthnContextClassRefBuilder authnContextClassRefBuilder;

    public SamlProfileSamlAuthNStatementBuilder(final OpenSamlConfigBean configBean,
                                                final AuthnContextClassRefBuilder authnContextClassRefBuilder) {
        super(configBean);
        this.authnContextClassRefBuilder = authnContextClassRefBuilder;
    }

    @Override
    public AuthnStatement build(final AuthnRequest authnRequest, 
                                final HttpServletRequest request,
                                final HttpServletResponse response,
                                final Assertion assertion, 
                                final SamlRegisteredService service,
                                final SamlRegisteredServiceServiceProviderMetadataFacade adaptor,
                                final String binding) throws SamlException {
        return buildAuthnStatement(assertion, authnRequest, adaptor, service);
    }

    /**
     * Creates an authentication statement for the current request.
     *
     * @param assertion    the assertion
     * @param authnRequest the authn request
     * @param adaptor      the adaptor
     * @param service      the service
     * @return constructed authentication statement
     * @throws SamlException the saml exception
     */
    private AuthnStatement buildAuthnStatement(final Assertion assertion, final AuthnRequest authnRequest,
                                               final SamlRegisteredServiceServiceProviderMetadataFacade adaptor,
                                               final SamlRegisteredService service) throws SamlException {

        final String authenticationMethod = this.authnContextClassRefBuilder.build(assertion, authnRequest, adaptor, service);
        final String id = '_' + String.valueOf(Math.abs(new SecureRandom().nextLong()));
        final AuthnStatement statement = newAuthnStatement(authenticationMethod, DateTimeUtils.zonedDateTimeOf(assertion.getAuthenticationDate()), id);
        if (assertion.getValidUntilDate() != null) {
            final ZonedDateTime dt = DateTimeUtils.zonedDateTimeOf(assertion.getValidUntilDate());
            statement.setSessionNotOnOrAfter(
                    DateTimeUtils.dateTimeOf(dt.plusSeconds(casProperties.getAuthn().getSamlIdp().getResponse().getSkewAllowance())));
        }
        statement.setSubjectLocality(buildSubjectLocality(assertion, authnRequest, adaptor));
        return statement;
    }

    /**
     * Build subject locality subject locality.
     *
     * @param assertion    the assertion
     * @param authnRequest the authn request
     * @param adaptor      the adaptor
     * @return the subject locality
     * @throws SamlException the saml exception
     */
    protected SubjectLocality buildSubjectLocality(final Assertion assertion, final AuthnRequest authnRequest,
                                                   final SamlRegisteredServiceServiceProviderMetadataFacade adaptor)
            throws SamlException {
        final SubjectLocality subjectLocality = newSamlObject(SubjectLocality.class);
        subjectLocality.setAddress(SamlIdPUtils.getIssuerFromSamlRequest(authnRequest));
        return subjectLocality;
    }
}

@@ -56,16 +56,61 @@
 lders;%0A%0A
+import org.apache.commons.lang3.StringUtils;%0A
 import o
@@ -274,57 +274,8 @@
 on;%0A
-import org.apereo.cas.support.saml.SamlIdPUtils;%0A
 impo
@@ -553,24 +553,69 @@
 eTimeUtils;%0A
+import org.apereo.cas.util.InetAddressUtils;%0A
 import org.j
@@ -807,16 +807,82 @@
 cality;%0A
+import org.opensaml.saml.saml2.metadata.AssertionConsumerService;%0A
 import o
@@ -1030,16 +1030,45 @@
 sponse;%0A
+import java.net.InetAddress;%0A
 import j
@@ -1978,17 +1978,16 @@
 Request,
- 
 %0A       
@@ -2171,17 +2171,16 @@
 sertion,
- 
 %0A       
@@ -2488,24 +2488,33 @@
 tor, service
+, binding
 );%0A    %7D%0A%0A  
@@ -2758,16 +2758,55 @@
 service%0A
+     * @param binding      the binding%0A
      * @
@@ -3207,16 +3207,38 @@
  service
+, final String binding
 ) throws
@@ -4056,16 +4056,25 @@
  adaptor
+, binding
 ));%0A    
@@ -4282,32 +4282,71 @@
     the adaptor%0A
+     * @param binding      the binding%0A
      * @return t
@@ -4647,16 +4647,89 @@
  adaptor
+,%0A                                                   final String binding
 )%0A      
@@ -4855,25 +4855,195 @@
     
-subjectLocality.s
+final AssertionConsumerService acs = adaptor.getAssertionConsumerService(binding);%0A        if (acs != null && StringUtils.isNotBlank(acs.getLocation())) %7B%0A            final String ip = In
 etAd
@@ -5051,16 +5051,8 @@
 ress
-(SamlIdP
 Util
@@ -5060,45 +5060,152 @@
 .get
-IssuerFromSamlRequest(authnRequest));
+ByName(acs.getLocation());%0A            if (StringUtils.isNotBlank(ip)) %7B%0A                subjectLocality.setAddress(ip);%0A            %7D%0A        %7D
 %0A   

clean up javadoc issues