Пример #1
0
  @Override
  protected void internalInit(final WebContext context) {
    CommonHelper.assertNotBlank("callbackUrl", this.callbackUrl);
    if (CommonHelper.isBlank(this.casLoginUrl) && CommonHelper.isBlank(this.casPrefixUrl)) {
      throw new TechnicalException("casLoginUrl and casPrefixUrl cannot be both blank");
    }

    initializeClientConfiguration();

    initializeLogoutHandler(context);

    if (this.casProtocol == CasProtocol.CAS10) {
      initializeCas10Protocol();
    } else if (this.casProtocol == CasProtocol.CAS20) {
      initializeCas20Protocol(context);
    } else if (this.casProtocol == CasProtocol.CAS20_PROXY) {
      initializeCas20ProxyProtocol(context);
    } else if (this.casProtocol == CasProtocol.CAS30) {
      initializeCas30Protocol(context);
    } else if (this.casProtocol == CasProtocol.CAS30_PROXY) {
      initializeCas30ProxyProtocol(context);
    } else if (this.casProtocol == CasProtocol.SAML) {
      initializeSAMLProtocol();
    }
    addAuthorizationGenerator(new DefaultCasAuthorizationGenerator<CasProfile>());
  }
Пример #2
0
  /**
   * Extracts digest Authorization header components. As per RFC 2617 : username is the user's name
   * in the specified realm qop is quality of protection uri is the request uri response is the
   * client response nonce is a server-specified data string which should be uniquely generated each
   * time a 401 response is made cnonce is the client nonce nc is the nonce count If in the
   * Authorization header it is not specified a username and response, we throw CredentialsException
   * because the client uses an username and a password to authenticate. response is just a MD5
   * encoded value based on user provided password and RFC 2617 digest authentication encoding rules
   *
   * @param context the current web context
   * @return the Digest credentials
   */
  @Override
  public DigestCredentials extract(WebContext context) throws HttpAction {
    final TokenCredentials credentials = this.extractor.extract(context);

    if (credentials == null) {
      return null;
    }

    String token = credentials.getToken();
    Map<String, String> valueMap = parseTokenValue(token);
    String username = valueMap.get("username");
    String response = valueMap.get("response");

    if (CommonHelper.isBlank(username) || CommonHelper.isBlank(response)) {
      throw new CredentialsException("Bad format of the digest auth header");
    }
    String realm = valueMap.get("realm");
    String nonce = valueMap.get("nonce");
    String uri = valueMap.get("uri");
    String cnonce = valueMap.get("cnonce");
    String nc = valueMap.get("nc");
    String qop = valueMap.get("qop");
    String method = context.getRequestMethod();

    return new DigestCredentials(
        response, method, clientName, username, realm, nonce, uri, cnonce, nc, qop);
  }
Пример #3
0
 protected void initializeClientConfiguration() {
   if (this.casPrefixUrl != null && !this.casPrefixUrl.endsWith("/")) {
     this.casPrefixUrl += "/";
   }
   if (CommonHelper.isBlank(this.casPrefixUrl)) {
     this.casPrefixUrl = this.casLoginUrl.replaceFirst("/login$", "/");
   } else if (CommonHelper.isBlank(this.casLoginUrl)) {
     this.casLoginUrl = this.casPrefixUrl + "login";
   }
 }
Пример #4
0
 protected void initializeClientConfiguration(final WebContext context) {
   if (this.casPrefixUrl != null && !this.casPrefixUrl.endsWith("/")) {
     this.casPrefixUrl += "/";
   }
   if (CommonHelper.isBlank(this.casPrefixUrl)) {
     this.casPrefixUrl = this.casLoginUrl.replaceFirst("/login$", "/");
   } else if (CommonHelper.isBlank(this.casLoginUrl)) {
     this.casLoginUrl = this.casPrefixUrl + "login";
   }
   this.casPrefixUrl = callbackUrlResolver.compute(this.casPrefixUrl, context);
   this.casLoginUrl = callbackUrlResolver.compute(this.casLoginUrl, context);
 }
Пример #5
0
 @Override
 public String getName() {
   if (CommonHelper.isBlank(this.name)) {
     return this.getClass().getSimpleName();
   }
   return this.name;
 }
Пример #6
0
 @Override
 protected void internalInit() {
   CommonHelper.assertNotBlank("callbackUrl", this.callbackUrl);
   CommonHelper.assertNotNull("logoutHandler", this.logoutHandler);
   if (CommonHelper.isBlank(this.casLoginUrl) && CommonHelper.isBlank(this.casPrefixUrl)) {
     throw new TechnicalException("casLoginUrl and casPrefixUrl cannot be both blank");
   }
   if (this.casPrefixUrl != null && !this.casPrefixUrl.endsWith("/")) {
     this.casPrefixUrl += "/";
   }
   if (CommonHelper.isBlank(this.casPrefixUrl)) {
     this.casPrefixUrl = this.casLoginUrl.replaceFirst("/login", "/");
   } else if (CommonHelper.isBlank(this.casLoginUrl)) {
     this.casLoginUrl = this.casPrefixUrl + "login";
   }
   if (this.casProtocol == CasProtocol.CAS10) {
     this.ticketValidator = new Cas10TicketValidator(this.casPrefixUrl);
   } else if (this.casProtocol == CasProtocol.CAS20) {
     this.ticketValidator = new Cas20ServiceTicketValidator(this.casPrefixUrl);
     if (this.casProxyReceptor != null) {
       final Cas20ServiceTicketValidator cas20ServiceTicketValidator =
           (Cas20ServiceTicketValidator) this.ticketValidator;
       cas20ServiceTicketValidator.setProxyCallbackUrl(this.casProxyReceptor.getCallbackUrl());
       cas20ServiceTicketValidator.setProxyGrantingTicketStorage(
           this.casProxyReceptor.getProxyGrantingTicketStorage());
     }
   } else if (this.casProtocol == CasProtocol.CAS20_PROXY) {
     this.ticketValidator = new Cas20ProxyTicketValidator(this.casPrefixUrl);
     final Cas20ProxyTicketValidator cas20ProxyTicketValidator =
         (Cas20ProxyTicketValidator) this.ticketValidator;
     cas20ProxyTicketValidator.setAcceptAnyProxy(this.acceptAnyProxy);
     cas20ProxyTicketValidator.setAllowedProxyChains(this.allowedProxyChains);
     if (this.casProxyReceptor != null) {
       cas20ProxyTicketValidator.setProxyCallbackUrl(this.casProxyReceptor.getCallbackUrl());
       cas20ProxyTicketValidator.setProxyGrantingTicketStorage(
           this.casProxyReceptor.getProxyGrantingTicketStorage());
     }
   } else if (this.casProtocol == CasProtocol.SAML) {
     this.ticketValidator = new Saml11TicketValidator(this.casPrefixUrl);
   }
 }
 @Override
 public void validate(final TokenCredentials credentials) throws HttpAction {
   if (credentials == null) {
     throw new CredentialsException("credentials must not be null");
   }
   if (CommonHelper.isBlank(credentials.getToken())) {
     throw new CredentialsException("token must not be blank");
   }
   final String token = credentials.getToken();
   final CommonProfile profile = new CommonProfile();
   profile.setId(token);
   credentials.setUserProfile(profile);
 }
Пример #8
0
  @Override
  protected void internalInit() {

    CommonHelper.assertTrue(
        CommonHelper.isNotBlank(this.idpMetadata) || CommonHelper.isNotBlank(this.idpMetadataPath),
        "Either idpMetadata or idpMetadataPath must be provided");
    CommonHelper.assertNotBlank("callbackUrl", this.callbackUrl);
    if (!this.callbackUrl.startsWith("http")) {
      throw new TechnicalException("SAML callbackUrl must be absolute");
    }

    if (CommonHelper.isNotBlank(this.keystorePath)
        || CommonHelper.isNotBlank(this.keystorePassword)
        || CommonHelper.isNotBlank(this.privateKeyPassword)) {
      CommonHelper.assertNotBlank("keystorePath", this.keystorePath);
      CommonHelper.assertNotBlank("keystorePassword", this.keystorePassword);
      CommonHelper.assertNotBlank("privateKeyPassword", this.privateKeyPassword);

      // load private key from the keystore and provide it as OpenSAML credentials
      this.credentialProvider =
          new CredentialProvider(this.keystorePath, this.keystorePassword, this.privateKeyPassword);
      this.decrypter = new EncryptionProvider(this.credentialProvider).buildDecrypter();
    }

    // Bootsrap OpenSAML
    try {
      DefaultBootstrap.bootstrap();
      NamedKeyInfoGeneratorManager manager =
          Configuration.getGlobalSecurityConfiguration().getKeyInfoGeneratorManager();
      X509KeyInfoGeneratorFactory generator = new X509KeyInfoGeneratorFactory();
      generator.setEmitEntityCertificate(true);
      generator.setEmitEntityCertificateChain(true);
      manager.registerFactory(Saml2Client.SAML_METADATA_KEY_INFO_GENERATOR, generator);
    } catch (ConfigurationException e) {
      throw new SamlException("Error bootstrapping OpenSAML", e);
    }

    // required parserPool for XML processing
    final StaticBasicParserPool parserPool = newStaticBasicParserPool();
    final AbstractMetadataProvider idpMetadataProvider = idpMetadataProvider(parserPool);

    final XMLObject md;
    try {
      md = idpMetadataProvider.getMetadata();
    } catch (MetadataProviderException e) {
      throw new SamlException("Error initializing idpMetadataProvider", e);
    }

    // If no idpEntityId declared, select first EntityDescriptor entityId as our IDP entityId
    if (this.idpEntityId == null) {
      this.idpEntityId = getIdpEntityId(md);
    }

    // Generate our Service Provider metadata
    Saml2MetadataGenerator metadataGenerator = new Saml2MetadataGenerator();
    if (this.credentialProvider != null) {
      metadataGenerator.setCredentialProvider(this.credentialProvider);
      metadataGenerator.setAuthnRequestSigned(true);
    }
    // If the spEntityId is blank, use the callback url
    if (CommonHelper.isBlank(this.spEntityId)) {
      this.spEntityId = getCallbackUrl();
    }
    metadataGenerator.setEntityId(this.spEntityId);
    // Assertion consumer service url is the callback url
    metadataGenerator.setAssertionConsumerServiceUrl(getCallbackUrl());
    // for now same for logout url
    metadataGenerator.setSingleLogoutServiceUrl(getCallbackUrl());
    AbstractMetadataProvider spMetadataProvider = metadataGenerator.buildMetadataProvider();

    // Initialize metadata provider for our SP and get the XML as a String
    try {
      spMetadataProvider.initialize();
      this.spMetadata = metadataGenerator.printMetadata();
    } catch (MetadataProviderException e) {
      throw new TechnicalException("Error initializing spMetadataProvider", e);
    } catch (MarshallingException e) {
      logger.warn("Unable to print SP metadata", e);
    }

    // Put IDP and SP metadata together
    ChainingMetadataProvider metadataManager = new ChainingMetadataProvider();
    try {
      metadataManager.addMetadataProvider(idpMetadataProvider);
      metadataManager.addMetadataProvider(spMetadataProvider);
    } catch (MetadataProviderException e) {
      throw new TechnicalException("Error adding idp or sp metadatas to manager", e);
    }

    // Build the contextProvider
    this.contextProvider =
        new Saml2ContextProvider(metadataManager, this.idpEntityId, this.spEntityId);

    // Get an AuthnRequest builder
    this.authnRequestBuilder =
        new Saml2AuthnRequestBuilder(forceAuth, comparisonType, destinationBindingType);

    // Build the WebSSO handler for sending and receiving SAML2 messages
    MessageEncoder encoder = null;
    if (SAMLConstants.SAML2_POST_BINDING_URI.equals(destinationBindingType)) {
      // Get a velocity engine for the HTTP-POST binding (building of an HTML document)
      VelocityEngine velocityEngine = VelocityEngineFactory.getEngine();
      encoder = new HTTPPostEncoder(velocityEngine, "/templates/saml2-post-binding.vm");
    } else if (SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(destinationBindingType)) {
      encoder = new HTTPRedirectDeflateEncoder();
    } else {
      throw new UnsupportedOperationException(
          "Binding type - " + destinationBindingType + " is not supported");
    }

    // Do we need binding specific decoder?
    MessageDecoder decoder = new Pac4jHTTPPostDecoder(parserPool);
    this.handler =
        new Saml2WebSSOProfileHandler(
            this.credentialProvider, encoder, decoder, parserPool, destinationBindingType);

    // Build provider for digital signature validation and encryption
    this.signatureTrustEngineProvider = new SignatureTrustEngineProvider(metadataManager);

    // Build the SAML response validator
    this.responseValidator = new Saml2ResponseValidator();
    if (this.maximumAuthenticationLifetime != null) {
      this.responseValidator.setMaximumAuthenticationLifetime(this.maximumAuthenticationLifetime);
    }
  }