Merge branch 'master' of https://github.com/wso2/carbon-device-mgt
commit
7e113a4805
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.wso2.carbon.webapp.authenticator.framework.authenticator;
|
||||||
|
|
||||||
|
import org.apache.axiom.om.OMElement;
|
||||||
|
import org.apache.axiom.om.impl.builder.StAXBuilder;
|
||||||
|
import org.apache.axiom.om.util.StAXUtils;
|
||||||
|
import org.apache.axiom.soap.SOAPEnvelope;
|
||||||
|
import org.apache.axiom.soap.SOAPHeader;
|
||||||
|
import org.apache.axiom.soap.SOAPHeaderBlock;
|
||||||
|
import org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder;
|
||||||
|
import org.apache.catalina.connector.Request;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.coyote.InputBuffer;
|
||||||
|
import org.apache.tomcat.util.buf.ByteChunk;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationException;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationFrameworkUtil;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.Utils.Utils;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuth2TokenValidator;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuthTokenValidationException;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuthValidationResponse;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.oauth.OAuthValidatorFactory;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class BSTAuthenticator implements WebappAuthenticator {
|
||||||
|
|
||||||
|
private Properties properties;
|
||||||
|
private OAuth2TokenValidator tokenValidator;
|
||||||
|
private static final List<String> APPLICABLE_CONTENT_TYPES = new ArrayList<>();
|
||||||
|
private static final Log log = LogFactory.getLog(BSTAuthenticator.class);
|
||||||
|
|
||||||
|
static {
|
||||||
|
APPLICABLE_CONTENT_TYPES.add("application/xml");
|
||||||
|
APPLICABLE_CONTENT_TYPES.add("application/soap+xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
if (this.properties == null) {
|
||||||
|
throw new IllegalArgumentException("Required properties needed to initialize OAuthAuthenticator " +
|
||||||
|
"are not provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = this.properties.getProperty("TokenValidationEndpointUrl");
|
||||||
|
if ((url == null) || (url.isEmpty())) {
|
||||||
|
throw new IllegalArgumentException("OAuth token validation endpoint url is not provided");
|
||||||
|
}
|
||||||
|
String adminUsername = this.properties.getProperty("Username");
|
||||||
|
if (adminUsername == null) {
|
||||||
|
throw new IllegalArgumentException("Username to connect to the OAuth token validation endpoint " +
|
||||||
|
"is not provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
String adminPassword = this.properties.getProperty("Password");
|
||||||
|
if (adminPassword == null) {
|
||||||
|
throw new IllegalArgumentException("Password to connect to the OAuth token validation endpoint " +
|
||||||
|
"is not provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRemote = Boolean.parseBoolean(this.properties.getProperty("IsRemote"));
|
||||||
|
|
||||||
|
Properties validatorProperties = new Properties();
|
||||||
|
validatorProperties.setProperty("MaxTotalConnections", this.properties.getProperty("MaxTotalConnections"));
|
||||||
|
validatorProperties.setProperty("MaxConnectionsPerHost", this.properties.getProperty("MaxConnectionsPerHost"));
|
||||||
|
this.tokenValidator =
|
||||||
|
OAuthValidatorFactory.getValidator(url, adminUsername, adminPassword, isRemote, validatorProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(Request request) {
|
||||||
|
String contentType = request.getContentType();
|
||||||
|
if (contentType.contains("application/xml") || contentType.contains("application/soap+xml") ||
|
||||||
|
contentType.contains("application/text")) {
|
||||||
|
try {
|
||||||
|
return isBSTHeaderExists(request);
|
||||||
|
} catch (IOException | XMLStreamException e) {
|
||||||
|
log.error("Error occurred while checking if BST authenticator can handle the incoming SOAP message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationInfo authenticate(Request request, Response response) {
|
||||||
|
String requestUri = request.getRequestURI();
|
||||||
|
String requestMethod = request.getMethod();
|
||||||
|
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
|
||||||
|
if ((requestUri == null) || ("".equals(requestUri))) {
|
||||||
|
authenticationInfo.setStatus(WebappAuthenticator.Status.CONTINUE);
|
||||||
|
return authenticationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(requestUri, "/");
|
||||||
|
String context = tokenizer.nextToken();
|
||||||
|
if ((context == null) || ("".equals(context))) {
|
||||||
|
authenticationInfo.setStatus(WebappAuthenticator.Status.CONTINUE);
|
||||||
|
}
|
||||||
|
String apiVersion = tokenizer.nextToken();
|
||||||
|
|
||||||
|
String authLevel = "any";
|
||||||
|
try {
|
||||||
|
if ("noMatchedAuthScheme".equals(authLevel)) {
|
||||||
|
AuthenticationFrameworkUtil.handleNoMatchAuthScheme(
|
||||||
|
request, response, requestMethod, apiVersion, context);
|
||||||
|
|
||||||
|
authenticationInfo.setStatus(WebappAuthenticator.Status.CONTINUE);
|
||||||
|
} else {
|
||||||
|
String bearerToken = request.getContext().findParameter("BST");
|
||||||
|
|
||||||
|
String resource = requestUri + ":" + requestMethod;
|
||||||
|
|
||||||
|
OAuthValidationResponse oAuthValidationResponse =
|
||||||
|
this.tokenValidator.validateToken(bearerToken, resource);
|
||||||
|
|
||||||
|
if (oAuthValidationResponse.isValid()) {
|
||||||
|
String username = oAuthValidationResponse.getUserName();
|
||||||
|
String tenantDomain = oAuthValidationResponse.getTenantDomain();
|
||||||
|
|
||||||
|
authenticationInfo.setUsername(username);
|
||||||
|
authenticationInfo.setTenantDomain(tenantDomain);
|
||||||
|
authenticationInfo.setTenantId(Utils.getTenantIdOFUser(username + "@" + tenantDomain));
|
||||||
|
if (oAuthValidationResponse.isValid())
|
||||||
|
authenticationInfo.setStatus(WebappAuthenticator.Status.CONTINUE);
|
||||||
|
} else {
|
||||||
|
authenticationInfo.setMessage(oAuthValidationResponse.getErrorMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
log.error("Failed to authenticate the incoming request", e);
|
||||||
|
} catch (OAuthTokenValidationException e) {
|
||||||
|
log.error("Failed to authenticate the incoming request due to oauth token validation error.", e);
|
||||||
|
}
|
||||||
|
return authenticationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "BSTAuthenticator";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Properties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Properties getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String name) {
|
||||||
|
return properties.getProperty(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] getUTF8Bytes(String soapEnvelope) {
|
||||||
|
byte[] bytes;
|
||||||
|
try {
|
||||||
|
bytes = soapEnvelope.getBytes("UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error("Unable to extract bytes in UTF-8 encoding. "
|
||||||
|
+ "Extracting bytes in the system default encoding"
|
||||||
|
+ e.getMessage());
|
||||||
|
bytes = soapEnvelope.getBytes();
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBSTHeaderExists(Request request) throws IOException, XMLStreamException {
|
||||||
|
String bstHeader = this.getBSTHeader(request);
|
||||||
|
if (bstHeader == null || bstHeader.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
request.getContext().addParameter("BST", bstHeader);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBSTHeader(Request request) throws IOException, XMLStreamException {
|
||||||
|
org.apache.coyote.Request coyoteReq = request.getCoyoteRequest();
|
||||||
|
InputBuffer buf = coyoteReq.getInputBuffer();
|
||||||
|
ByteChunk bc = new ByteChunk();
|
||||||
|
|
||||||
|
buf.doRead(bc, coyoteReq);
|
||||||
|
try (InputStream is = new ByteArrayInputStream(getUTF8Bytes(bc.toString()))) {
|
||||||
|
XMLStreamReader reader = StAXUtils.createXMLStreamReader(is);
|
||||||
|
StAXBuilder builder = new StAXSOAPModelBuilder(reader);
|
||||||
|
SOAPEnvelope envelope = (SOAPEnvelope) builder.getDocumentElement();
|
||||||
|
envelope.build();
|
||||||
|
|
||||||
|
SOAPHeader header = envelope.getHeader();
|
||||||
|
Iterator headerEls = header.getChildrenWithLocalName("Security");
|
||||||
|
if (!headerEls.hasNext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
OMElement securityHeader = (OMElement) headerEls.next();
|
||||||
|
Iterator securityHeaderEls = securityHeader.getChildrenWithLocalName("BinarySecurityToken");
|
||||||
|
if (!securityHeaderEls.hasNext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
OMElement bstHeader = (OMElement) securityHeaderEls.next();
|
||||||
|
bstHeader.build();
|
||||||
|
return bstHeader.getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.wso2.carbon.webapp.authenticator.framework.test;
|
||||||
|
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.WebappAuthenticatorRepository;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.test.util.MalformedAuthenticator;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.test.util.TestWebappAuthenticator;
|
||||||
|
|
||||||
|
public class WebappAuthenticatorRepositoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAuthenticator() {
|
||||||
|
WebappAuthenticatorRepository repository = new WebappAuthenticatorRepository();
|
||||||
|
|
||||||
|
WebappAuthenticator addedAuthenticator = new TestWebappAuthenticator();
|
||||||
|
repository.addAuthenticator(addedAuthenticator);
|
||||||
|
|
||||||
|
WebappAuthenticator retriedAuthenticator = repository.getAuthenticator(addedAuthenticator.getName());
|
||||||
|
Assert.assertEquals(addedAuthenticator.getName(), retriedAuthenticator.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
|
public void testAddMalformedAuthenticator() {
|
||||||
|
WebappAuthenticatorRepository repository = new WebappAuthenticatorRepository();
|
||||||
|
WebappAuthenticator malformedAuthenticator = new MalformedAuthenticator();
|
||||||
|
repository.addAuthenticator(malformedAuthenticator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
|
public void testAddAuthenticatorWithNull() {
|
||||||
|
WebappAuthenticatorRepository repository = new WebappAuthenticatorRepository();
|
||||||
|
repository.addAuthenticator(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = IllegalStateException.class)
|
||||||
|
public void testAddAuthenticatorWithEmptyString() {
|
||||||
|
WebappAuthenticatorRepository repository = new WebappAuthenticatorRepository();
|
||||||
|
repository.addAuthenticator(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.wso2.carbon.webapp.authenticator.framework.test.util;
|
||||||
|
|
||||||
|
import org.apache.catalina.connector.Request;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class MalformedAuthenticator implements WebappAuthenticator {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(Request request) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationInfo authenticate(Request request, Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Properties properties) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Properties getProperties() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.wso2.carbon.webapp.authenticator.framework.test.util;
|
||||||
|
|
||||||
|
import org.apache.catalina.connector.Request;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.AuthenticationInfo;
|
||||||
|
import org.wso2.carbon.webapp.authenticator.framework.authenticator.WebappAuthenticator;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class TestWebappAuthenticator implements WebappAuthenticator {
|
||||||
|
|
||||||
|
private static final String NAME = "TestAuthenticator";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandle(Request request) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationInfo authenticate(Request request, Response response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperties(Properties properties) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Properties getProperties() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in new issue