/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.picketlink.identity.federation.bindings.jboss.auth;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.jacc.PolicyContext;
import javax.servlet.http.HttpServletRequest;
import org.jboss.security.auth.spi.AbstractServerLoginModule;
import org.picketlink.identity.federation.PicketLinkLogger;
import org.picketlink.identity.federation.PicketLinkLoggerFactory;
import org.picketlink.identity.federation.core.util.Base64;
import org.picketlink.identity.federation.core.wstrust.SamlCredential;
/**
* This is not login module with full functionality.
* It just adds ability to get SAML token from http header specified by module option.
*
* @author Peter Skopek: pskopek at redhat dot com
*
*/
public abstract class SAMLTokenFromHttpRequestAbstractLoginModule extends
AbstractServerLoginModule {
protected static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger();
protected String tokenEncoding = SAML2STSCommonLoginModule.NONE_TOKEN_ENCODING;
/**
* Specify which http header contains saml token.
* If null, default behavior will be used, credentials got from callback.
*/
private String samlTokenHttpHeader = null;
/**
* Regular expression to parse samlTokenHttpHeader to obtain saml token only.
* Token itself has to be Base64 encoded.
* Use .* to match whole content.
*/
private String samlTokenHttpHeaderRegEx = null;
private Pattern pattern = null;
/**
* Group which will be used to retrieve matched part of the token header content.
* Defaults to 0.
* pattern.matcher.group(samlTokenHttpHeaderRegExGroup)
*/
private int samlTokenHttpHeaderRegExGroup = 0;
/**
* Key to specify token compression.
* Supported types:
* {@link GZIP_TOKEN_ENCODING} - gzip
* {@link BASE64_TOKEN_ENCODING} - base64
* {@link NONE_TOKEN_ENCODING} - none
*/
public static final String TOKEN_ENCODING_TYPE_KEY = "tokenEncodingType";
/**
* Token encoding type: gzip
*/
public static final String GZIP_TOKEN_ENCODING = "gzip";
/**
* Token encoding type: none
*/
public static final String NONE_TOKEN_ENCODING = "none";
/**
* Token encoding type: base64
*/
public static final String BASE64_TOKEN_ENCODING = "base64";
public static final String WEB_REQUEST_KEY = "javax.servlet.http.HttpServletRequest";
public static final String REG_EX_PATTERN_KEY = "samlTokenHttpHeaderRegEx";
public static final String REG_EX_GROUP_KEY = "samlTokenHttpHeaderRegExGroup";
public static final String SAML_TOKEN_HTTP_HEADER_KEY = "samlTokenHttpHeader";
protected SamlCredential getCredentialFromHttpRequest() throws Exception {
HttpServletRequest request = (HttpServletRequest) PolicyContext.getContext(WEB_REQUEST_KEY);
String encodedSamlToken = null;
if (samlTokenHttpHeaderRegEx != null && !samlTokenHttpHeaderRegEx.equals("")) {
String content = request.getHeader(samlTokenHttpHeader);
if (logger.isTraceEnabled()) {
log.trace("http header with SAML token [" + samlTokenHttpHeader + "]=" + content);
}
log.trace("samlTokenHttpHeaderRegEx="+samlTokenHttpHeaderRegEx);
Matcher m = pattern.matcher(content);
m.matches();
log.trace("samlTokenHttpHeaderRegExGroup="+samlTokenHttpHeaderRegExGroup);
encodedSamlToken = m.group(samlTokenHttpHeaderRegExGroup);
}
else {
encodedSamlToken = request.getHeader(samlTokenHttpHeader);
}
if (logger.isTraceEnabled()) {
logger.trace("encodedSamlToken="+encodedSamlToken);
}
String samlToken = null;
if (tokenEncoding.equals(NONE_TOKEN_ENCODING)
|| tokenEncoding == null) {
samlToken = encodedSamlToken;
}
else {
// gzip and base64 encodings are handled in this Base64.decode call
byte[] decompressed = Base64.decode(encodedSamlToken);
samlToken = new String(decompressed);
}
if (logger.isTraceEnabled()) {
logger.trace("decoded samlToken="+samlToken);
}
return new SamlCredential(samlToken);
}
/**
* @return the tokenEncoding
*/
public String getTokenEncoding() {
return tokenEncoding;
}
/**
* @return the samlTokenHttpHeader
*/
public String getSamlTokenHttpHeader() {
return samlTokenHttpHeader;
}
/**
* @return the samlTokenHttpHeaderRegEx
*/
public String getSamlTokenHttpHeaderRegEx() {
return samlTokenHttpHeaderRegEx;
}
/**
* @return the samlTokenHttpHeaderRegExGroup
*/
public int getSamlTokenHttpHeaderRegExGroup() {
return samlTokenHttpHeaderRegExGroup;
}
/* (non-Javadoc)
* @see org.jboss.security.auth.spi.AbstractServerLoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
*/
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
super.initialize(subject, callbackHandler, sharedState, options);
samlTokenHttpHeader = (String)this.options.get(SAML_TOKEN_HTTP_HEADER_KEY);
String encoding = (String)this.options.get(TOKEN_ENCODING_TYPE_KEY);
if (encoding != null) {
this.tokenEncoding = encoding;
}
samlTokenHttpHeaderRegEx = (String)this.options.get(REG_EX_PATTERN_KEY);
if (samlTokenHttpHeaderRegEx != null) {
this.pattern = Pattern.compile(samlTokenHttpHeaderRegEx, Pattern.DOTALL);
}
String group = (String)this.options.get(REG_EX_GROUP_KEY);
if (group != null) {
samlTokenHttpHeaderRegExGroup = Integer.parseInt(group);
}
}
}