I am trying to learn about authentication in JAX-WS, so I made a small Netbeans8.0.2/Glassfish4.1 web application with a JAX-WS webservice, and I am trying to make it not public, but available to authorized users only.
The web.xml file for this webservice contains:
<security-constraint>
<web-resource-collection>
<web-resource-name>Fib Web Service</web-resource-name>
<url-pattern>/FibServiceWithAuth/*</url-pattern>
<http-method>*</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
However, when I make another simple web app that is using this service,
it works without any authentication required, see here:
http://kempelen.ii.fmph.uniba.sk:8080/FibApp/
I understand that I should connect to the service from the JSF managed bean that handles this JSF page like this:
package fibapp;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.WebServiceRef;
#ManagedBean
#RequestScoped
public class FibBean
{
public FibBean() { }
int n;
String result;
public int getN() { return n; }
public void setN(int newN) { n = newN; }
public String getResult() { return result; }
public void setResult(String newResult) { result = newResult; }
#WebServiceRef(wsdlLocation = "http://kempelen.ii.fmph.uniba.sk:8080/FibServiceWithAuth/FibWithAuth?wsdl")
private FibWithAuth_Service fibService;
public void compute()
{
FibWithAuth fib = fibService.getFibWithAuthPort();
// ((BindingProvider) fib).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "someuser");
// ((BindingProvider) fib).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "somepass");
result = fib.fib(n).toString();
}
}
but even when those user/pass lines are commented out, the bean still gets the result from the webservice.
What is missing, please?
In looking at your WSDL (as specified in your managed bean's #WebServiceRef), the endpoint of the service is
<soap:address
location="http://kempelen.ii.fmph.uniba.sk:8080/FibServiceWithAuth/FibWithAuth"/>
which means your web service resource is /FibWithAuth.
However, your web.xml <security-constraint> url is
<url-pattern>/FibServiceWithAuth/*</url-pattern>
I think you want to change this to
<url-pattern>/FibWithAuth/*</url-pattern>
If you truly want to add the security constraint to the entire FibServiceWithAuth web application, then your <security-constraint> url pattern would be /*.
Lastly, I think you'll also want to change
<http-method>*</http-method>
to
<http-method>POST</http-method>
so that your managed bean can access the WSDL via GET request (per your #WebServiceRef annotation) without authentication.
Related
I've got a jax-ws webservice which I need to secure. When I start wildfly everything seems to load nicely, but when I try to send a request via SOAPUI tool, the server returns Error with body element - unauthorized. Relevant parts of code below.
Webservice itself:
#WebService
#Stateless
#RolesAllowed("testrole")
#SecurityDomain("test-domain")
public class Test {
#WebMethod
#WebResult(name = "HelloResponse")
public String sayHello(#WebParam(name = "username") String name) {
return "Hello " + name;
}
}
standalone.xml:
<security-domain name="test-domain" cache-type="default">
<authentication>
<login-module code="org.jboss.security.auth.spi.UserRolesLoginModule"
flag="required">
<module-option name="userProperties" value="test-domain-users.properties" relative-to="jboss.server.config.dir"/>
<module-option name="rolesProperties" value="test-domain-roles.properties" relative-to="jboss.server.config.dir"/>
</login-module>
</authentication>
</security-domain>
jboss-web.xml:
<jboss-web>
<security-domain>test-domain</security-domain>
</jboss-web>
test-domain-users.properties and test-domain-roles.properties look like this:
testuser=testpassword, testuser=testrole
I have written Webservice in java which has successfully created WSDL. I am stuck in writing a webservice client for my webservice in java. I would like to use my webservice from some jsp classes. How do i do it?
#WebService
public interface AddService {
double getMultipicationResult(double M1, double M2);
}
#WebService(endpointInterface = "com.sample.AddService")
public class AddServiceImpl implements AddService {
public AddServiceImpl() {
}
#Override
public double getMultipicationResult(double M1, double M2) {
M1 = M1*M2;
return M1;
}
}
I have written the client something like :-
public class AddServiceClient {
private AddServiceClient() {
}
public static void main(String args[]){
{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"SpringClientWebServices.xml"});
AddService client = (AddService)context.getBean("client");
double response = 0.0;
response = client.getMultipicationResult(10.0, 20.5);
}
}
and SpringClientWebServices.xml is as follows :-
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="client" class="com.sample.AddService"
factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.sample.AddService"/>
<property name="address" value="http://localhost:8080/sample/services/Addition"/>
</bean>
</beans>
I am getting exception as follows:-
Exception in thread "main" org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.apache.cxf.jaxws.JaxWsProxyFactoryBean] for bean with name 'clientFactory' defined in class path resource [SpringClientWebServices.xml]; nested exception is java.lang.ClassNotFoundException: org.apache.cxf.jaxws.JaxWsProxyFactoryBean
First of all you are missing the CXF jars as evident from the ClassNotFoundException. Please include the cxf jars.
Second regarding using the service in JSPs then you have to first initialize the Spring container via web.xml and not via main method. Use Spring MVC and implement controller which makes calls to webservice and provide data to the JSP.
If you want to consume a service directly from the JSP, consider a JavaScript client like mentioned: http://cxf.apache.org/docs/javascript-client-samples.html
I prefer to use a jar that contains the service interface and create a dynamic Spring client using CXF and Spring in a separate jar, then bring in both f those dependencies. This is also documented in the CXF site.
I need to configure the camel route endpoint using WSDL file.
I don't know the service classes and I don't want to put the service class files in my class path. I have only the WSDL file.
How can I solve my task ?
Define the camel cxf endpoint as follows
<cxf:cxfEndpoint id="testServiceEndpoint" address="http://localhost:9000/web-service/TestService" wsdlURL="TestService.wsdl" serviceClass="com.webservice.AllServiceService" endpointName="s:TestServiceHttpSoap11Endpoint" serviceName="s:TestPutService" xmlns:s="http://webservices/testService"/>
Route configuration
<route>
<from uri="cxf:bean:testServiceEndpoint"/>
<to uri="log:output?showAll=true" />
</route>
Note that I have mentioned a serviceClass attribute, but this class can be made generic to handle all webservices by using #WebServiceProvider annotation
#WebServiceProvider
#ServiceMode(Mode.PAYLOAD)
public class AllServiceService implements Provider<StreamSource> {
#Override
public StreamSource invoke(StreamSource request) {
}
}
Desperately need help here securing a simple Apache CXF web service. Attempts with Spring Security is taking me no where so I need to find a different strategy. This is to implement authorization on a legacy Java service implemented for some of our clients.
This simple Apache CXF web service was created using Maven's cxf-jaxws-javafirst prototype.
It produced a web.xml and beans.xml file and sample code. Besides beans.xml which remains in default state, I have modified these entities as follows:
web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>WEB-INF/shiro.ini</param-value>
</context-param>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
and my Shiro.ini file looks like this:
# =======================
# Shiro INI configuration
# =======================
[main]
authc = org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
[users]
o = o, OPERATOR
a = a, ADMIN
s = s, SUPERVISOR
[roles]
SUPERVISOR = *
ADMIN = sayHiAdmin
OPERATOR = deleteAccounts
My simple webservice code is as follows:
import javax.jws.WebService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
#WebService(endpointInterface = "org.myCo.com.CxfShiroSecuredService.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String text) {
if (isAuthorized("sayHi")) {
return "Successfully said hi " + text;
}
if (hasRole("OPERATOR")){
return "User is OPERATOR";
}
if (hasRole("ADMIN")){
return "User is OPERATOR";
}
throw new UnauthorizedException("Logged user does not have OPERATOR's permission");
}
public String sayHiAdmin(String text) {
if (isAuthorized("sayHiAdmin")) {
return "Successfully said hi Admin " + text;
}
throw new UnauthorizedException("Logged user does not have ADMIN permission");
}
public String deleteAccounts(String text) {
if (isAuthorized("deleteAccounts")) {
return "Successfully deleted accounts " + text;
}
throw new UnauthorizedException("Logged user does not have SUPERVISOR permission");
}
private Boolean isAuthorized(String operation){
Subject currentUser = SecurityUtils.getSubject();
return currentUser.isPermitted(operation); //currentUser.isAuthenticated(); // && currentUser.isPermitted(operation);
}
private Boolean hasRole(String role){
Subject currentUser = SecurityUtils.getSubject();
return currentUser.hasRole(role);
}
}
I have a C# test client that passes authentication information in the SOAP header before invoking webservice like so:
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var client = new HelloWorldClient();
var response = "";
using (new OperationContextScope(client.InnerChannel))
{
var httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " +
Convert.ToBase64String(Encoding.ASCII.GetBytes(UserName.Text + ":" + Password.Text));
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
try
{
response = client.sayHi("hi " + UserName.Text);
}
catch (TimeoutException tex)
{
response = tex.Message;
}
catch (CommunicationException cex)
{
response = cex.Message;
}
}
TextBox.Text = response;
}
I have used this same strategy for other web services that require Basic authentication
before invoking method calls with success but this service does not seem to be recognizing my credentials. For each method call invoked, regardless of username/password combination, I get the UnAuthorizedException thrown. Can someone shed me some light?
Thanks in advance.
You need a [urls] section in your shiro.ini file. Something like this:
[urls]
/** = authc
Check out the documentation for further details here.
In this hypothetical scenario there is an ASP.NET 4 web application that simultaneously aggregates data from multiple web services. The web services are all of the same implementation, but are separate instances and are not aware of each other.
In the web application a user provides credentials for each web service he wants access to, and the authentication process iterates through all of his user name/password combos coupled with the URL for each web service. (The clunky UI is for illustration only....)
Assume the web application uses the ValidateUser method in a custom MembershipProvider class for authentication, and the MembershipProvider is configured in web.config as per usual.
Assume also that the custom MembershipProvider class has a Url property that changes with each authentication call to the different web services.
Assuming all of that, how do you handle the scenario where User 1 and User 2 are authenticating at the same time, but User 1 has access to Web Service A, B, and C, and User 2 has access to Web Service X, Y, and Z?
Will the credentials and URLs potentially get mixed up and User 1 might see User 2's data and vice-versa?
If you are going to implement a custom membership provider you will see lots of headaches down the road. The reason is that in your app model, the authorization scheme is based on whatever membership the user has (for a specific service).
I would advise to have your own membership (for your own site) and extend the profile model so that you can retrieve credentials for each service that the user has access to straight out of the user's profile.
The profile information can be used in conjunction with your own authorization based on your own membership and role providers (specific for your site). In that case you can assign each user a role specific to each service.
To successfully achieve that, for each service, write a wrapper, encapsulating service calls with your own methods (which call the service). This will allow you to mark your own methods with the [PrincipalPermissison] attribute... and achieve seemless authorization.
So if your user has access to the Amazon web service and there are credentials for that service stored in his/her profile you can have the following:
User Role: "AmazonAccessor"
public AmazonServiceWrapper
{
[PrincipalPermission(SecurityAction.Demand, Role = "AmazonAccessor")]
public void DoSomething()
{
UserProfile profile = UserProfile.Get();
ServiceCredential credential = (ServiceCredential)(from c in profile.ServiceCredentials where c.ServiceName = "Amazon" select c).Take(1);
if( credential == null )
return;
AmazonService amazon = new AmazonService();
amazon.ClientCredentials.UserName.UserName = credential.Username; //coming from profile
amazon.ClientCredentials.UserName.Password = credential.Password; //coming from profile
try{
amazon.DoSomething(); //wrap the amazon call.
}
catch(Exception ex)
{
}
}
}
This will prevent you from having to juggle membership and all sorts of other headaches.
Now to create your own profile you can do something like this:
[Serializable]
public class ServiceCredential
{
public string ServiceName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string ServiceUrl { get; set; }
}
public class UserProfile : ProfileBase
{
public static UserProfile Get(string username)
{
return (UserProfile)Create(username);
}
public static UserProfile Get()
{
return (UserProfile)Create(Membership.GetUser().UserName);
}
[SettingsAllowAnonymous(false)]
public List<ServiceCredential> ServiceCredentials
{
get
{
try
{
return base.GetPropertyValue("ServiceCredentials") as List<ServiceCredential>;
}
catch
{
return new List<ServiceCredential>();
}
}
set
{
base.SetPropertyValue("ServiceCredentials", value);
}
}
}
And of course the Web config:
<system.Web>
<profile
inherits="MyApplication.UserProfile"
defaultProvider="AspNetSqlProfileProvider">
<providers>
<add
name="MyProfileProvider"
type="System.Web.Profile.SqlProfileProvider"
connectionStringName="MyConnectionString"
applicationName="MyApplication" />
</providers>
</profile>
<system.Web>