Has anyone successfully secured a web service using Active Directory credentials instead of an application specific username/password?
I have an application that talks to web services written with Axis2 1.5.1 and deployed on Tomcat 6.0.24, deployed on Linux, FWIW.
I have changed Tomcat from a JDBCRealm, authenticating against a database, to a JAASRealm, configured to access AD with Centrify (the client's preferred solution).
This works with web applications but for web services I get a 403 response.
I have tested using a simple Axis2 service (written with Axis2 1.5.1) and deployed against Tomcat 6.0.24 and 7.0.63. I've also tried with a web service written using Axis2 1.6.2. I get the same result in each case. I'm testing using a browser, BTW. When the service works I get xml; when it doesn't I get the error.
I'm wondering whether I need to change something in axis2.xml since even https://tomcat:8443/HelloWorld (my service is called HelloWorld) generates a 403.
Some configuration details...
I've changed the realm in server.xml to the following
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassName="com.centrify.dc.tomcat.RolesPrincipal"
userClassName="com.centrify.dc.tomcat.LoginPrincipal" />
<Valve className="com.centrify.dc.tomcat.ContextValve" />
In web.xml I have added
<security-constraint>
<display-name>Security Web Service</display-name>
<web-resource-collection>
<web-resource-name>Secured Area</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>SPNEGO</auth-method>
<realm-name>CENTRIFYDC</realm-name>
</login-config>
<!-- Security roles referenced by this web application -->
<security-role>
<role-name>USER</role-name>
</security-role>
I've mapped the USER role to one of my AD groups
Any suggestions or guidance or setups that have worked for someone would be very useful, thanks.
The 403 error is indicating the permission problem after authentication. It is because after SSO, the server will check for group membership to see if the user got proper permission. The 403 error is coming from the configuration part of role mapping. SSO to the server is actually working fine.
We would suggest you to try the following(the following example is using 5.5 version tomcat but it will be the same for later version):
Configure tomcat for Centrify
a. Configure tomcat for Centrify by using configure.pl:
cd /usr/share/centrifydc/java
./configure.pl
Enter /opt/apache-tomcat-5.5.25 when prompted for the tomcat directory.
Enter /usr/jdk1.5.0_15 when prompted for the java directory.
Enter y when prompted if you want to configure Tomcat for SSL
Enter n when prompted if you want to configure Tomcat for SSL communication with ADFS server
Take default for everything else.
Configure webdav for Centrify and use kerberos(SPNEGO) for authentication
a. Set the logon realm to CENTRIFYDC:
cd /opt/apache-tomcat-5.5.25/webapps/
mkdir webdav/META-INF
create webdav/META-INF/context.xml as:
<Context path="/webdav">
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassNames="com.centrify.dc.tomcat.RolesPrincipal"
userClassNames="com.centrify.dc.tomcat.LoginPrincipal"/>
<Valve className="com.centrify.dc.tomcat.ContextValve"/> </Context>
b. Configure mapping of AD groups to roles for the jspwiki app.
cp /usr/share/centrifydc/java/templates/centrifydc.xml webdev/WEB-INF/centrifydc.xml
modify RoleMapping section in webdev/WEB-INF/centrifydc.xml as follow:
<RoleMapping separator=";">
<Role name="user" group="*" user="*"/>
<Role name="#ROLE2#" group="#GROUP2#"/>
<Role name="#ROLE3#" user="#USER3#"/>
</RoleMapping>
c. Configure web.xml to use kerberos(SPNEGO) for authentication:
Edit web.xml and add
<login-config>
<auth-method>SPNEGO</auth-method>
<realm-name>Default</realm-name>
</login-config>
<!--
OPTIONAL: Add CentrifyFilter to set the authenticated user's attributes
such as group membership in HTTP headers. You must also configure the
<SetHeaders> element in centrifydc.xml to set user attributes in HTTP
headers.
This filter is not needed if you do not want the authenticated
user's attributes set in HTTP headers.
-->
<filter>
<filter-name>CentrifyFilter</filter-name>
<filter-class>com.centrify.dc.wbase.DCFilter</filter-class>
</filter>
<!--
OPTIONAL: Apply (map) CentrifyFilter to the url patterns in the
<security-constraint> section of this application to set the
authenticated user's attributes in HTTP headers.
This <filter-mapping> is not needed if you do not want the
authenticated user's attributes set in HTTP headers.
-->
<filter-mapping>
<filter-name>CentrifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>ProtectedResource</web-resource-name>
<url-pattern>/index.html</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<description>
An test role
</description>
<role-name>user</role-name>
</security-role>
You could also refer to the Centrify Java Guide p.135 for the example for role mapping configured as follow:
Extensible Markup Language (XML) files, like the centrifydc.xml file, are structured documents that contain a set of supported elements enclosed in opening and closing angle (< >) brackets. The elements can be required or optional depending on the requirements of the application. The following is an example of how the key elements defined in the centrifydc.xml file:
<Centrifydc>
<enableAuthSchemes>Negotiate,NTLM,Basic</enableAuthSchemes>
<adclientSocket>/var/centrifydc/daemon</adclientSocket>
<RoleMapping>
<Role name=”role1” group=”arcade.com/Users/Sales”/>
</RoleMapping>
</Centrifydc>
Although the template centrifydc.xml file contains some default settings, these default settings should be modified in the copy of the centrifydc.xml file you place in an application’s WEB-INF directory. The following table describes the elements you can set in the centrifydc.xml file.
If you need any further assistance, please feel free to contact Centrify Technical Support directly.
There were a couple of problems. The first was an error was in the server.xml file. JAASRealms can accept several classes for role and user so the properties are roleClassNames and userClassNames as follows
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="CENTRIFYDC"
roleClassNames="com.centrify.dc.tomcat.RolesPrincipal"
userClassNames="com.centrify.dc.tomcat.LoginPrincipal" />
The second issue is around using several applications which use different authorization. The centrifydc.xml file maps roles when the app is first authenticated. However, if org.apache.catalina.authenticator.SingleSignOn is enabled then the roles are set only for the application that performs the authentication. Thereafter, only the roles set in the authenticating application's centrifydc.xml file are set. Other applications will see that the user is already authenticated but does not have the necessary authorization and fail with a 403 error.
In different applications use the roles user, USER and manager then the logging-in application must set up all three roles when it authenticates.
Related
I am using a glassfish server and implementing Rest webservices which can be consumed from web or mobile clients.
I now want to secure these webservices using ssl certificates and create a session between client and server. I have not yet purchased any domain name or server space and trying to build it on my local machine.
How do i configure a free ssl certificate for glassfish on my localhost.
Thanks,
Pavan
Hotcoder24,
As far as I understand the problem from your question and comment, you want to communicate with your service via HTTPS. This is a snap when you use an application server. In fact, this is done with configuration in your web.xml file.
Let's start with a simple web application created using maven archetype jersey-quickstart-webapp, described in Jersey tutorial.
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.example -DartifactId=simple-service-webapp -Dpackage=com.example -DarchetypeVersion=2.14
This creates a web application containing a single resource, which can be deployed to a Glassfish server (a war-file is produced).
#Path("myresource")
public class MyResource {
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getIt() {
return "Got it!";
}
}
First of all, you should create a user and add it to a group using Glassfish console (http://localhost:4848/). The simplest way to start is to use a file realm. The process is described here. Let's create a user called “user” and group called “users”.
If you deploy the application, the resource will be available in your browser if you enter a URL http://localhost:8080/simple-service-webapp/webapi/myresource. Before we have done any configuration in the project's xml files, the resource is freely available.
Now let's add some elements to your web.xml file.
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--Some elements go here-->
<security-constraint>
<web-resource-collection>
<web-resource-name>GetIt</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>users</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>file</realm-name>
</login-config>
<security-role>
<role-name>users</role-name>
</security-role>
We added tree elements:
security-constraint which describes a URL pattern to protect, lists roles allowed to access it and most important to your question is the user-data-constraint element, which in our case switches on the HTTPS.
login-config element instructs the server to use the simplest authenticated mechanism which means, that when you try to access the resource using a browser, a dialog prompting for login and password is displayed to you; also you realm's name is enshrined here;
the last element defines roles you use.
Now it is necessary that groups are linked to roles. This is done using a container-specific glassfish-web.xml.
<glassfish-web-app error-url="">
<security-role-mapping>
<role-name>users</role-name>
<group-name>users</group-name>
</security-role-mapping>
<!--some elements go here-->
Now if you direct your browser to a http:// URL, you'll be switched to https://, which is not the case without the user-data-constraint element with <transport-guarantee>CONFIDENTIAL</transport-guarantee>.
What would be the URL for the newly set up SAML SSO's metadata URL, or how could I download this in XML format from WSO2 Identity Server (version 4.6.0) acting as IdP?
Thanks,
Tamas
WSO2 Identity server now hosts IDPSSODesriptor metadata file on this URL.
https://localhost:9443/identity/metadata/saml2
This feature is available from Identity Server version 5.3 onward.
AFAIK there is no option to auto-generate metadata files for IS. You have to manually write the metadata file. An example is as follows, taken from this blog post.
<md:entitydescriptor entityid="https://localhost:9443/samlsso" validuntil="2023-09-23T06:57:15.396Z" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<md:idpssodescriptor protocolsupportenumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:keydescriptor use="signing">
<ds:keyinfo>
<ds:x509data>
<ds:x509certificate>MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxv
Y2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UE
AwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTou
sMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5
HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQID
AQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44i
QlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJR
O4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo=</ds:x509certificate>
</ds:x509data>
</ds:keyinfo>
</md:keydescriptor>
<md:singlelogoutservice binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" location="https://localhost:9443/samlsso" responselocation="https://localhost:9443/samlsso">
<md:singlesignonservice binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" location="https://localhost:9443/samlsso">
<md:singlesignonservice binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" location="https://localhost:9443/samlsso">
</md:singlesignonservice></md:singlesignonservice></md:singlelogoutservice></md:idpssodescriptor>
</md:entitydescriptor>
Yes.. Identity Server does not support to generate a IDP information as metadata file. You may need to create it manually. But I guess it would be available with a future release. There is an open public jira for this. You can find a generated SAML2 metadata file from here. However you may need to configure it according to your configurations. If you have changed your keystore, you need to change the X509 certificate data. And also urls of the samlsso endpoint. By default saml sso end point is located at https://localhost:9443/samlsso. In your service provider config, you need to configure this url as IDP url (both login and logout). You must provide the wso2carbon certificate in to service provider for validating the signature.
i'm developing a webservice with ejb 3 and glassfish 3.1.1. I'm using Netbeans 7.0 and would like to know, how to enable https on port 8181 for this webservice.
I dont need any authentication method, just secure the communication through https!
Thx
Adem
You need to specify a secure connection as explained here. Essentially, in your deployment descriptor web.xml you need to set:
<security-constraint>
...
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
However NetBeans will insert the code for you: open web.xml, click the Security tab along the top of the editor, then click the Add Security Constraint button. Type a name, in URL pattern write /*, set All Http Methods, and specify Confidential as Transport Guarantee.
If you don't have web.xml, because you are deploying just the Enterprise Java Bean, create a New GlassFish Descriptor glassfish-ejb-jar.xml and fill it like this (or see here the file hierarchy):
<glassfish-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>Hello</ejb-name>
<webservice-endpoint>
<port-component-name>Hello</port-component-name>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</webservice-endpoint>
</ejb>
</enterprise-beans>/>
</glassfish-ejb-jar>
Your application will use port 8181 from now on.
See here for further information about how to setup security in a Netbeans web application and here for learning about certificates.
I have a webservice and a Silverlight application.
I also have a crossdomain.xml and clientaccesspolicy.xml
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
here my cross domain policy
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="http://localhost/MHVWS/MachineHistoryWS.asmx" />
</cross-domain-policy>
My web service is being hosted in IIS.
With this configuration I still have this kind of error:
An error occurred while trying to make a request to URI 'http://localhost/MHVWS/MachineHistoryWS.asmx'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details.
Please help
You only need one policy file. You dont require both.
Be sure one (or both) of those policy files exist in the same location (domain) as the webservice.
To debug and see what is going on, use a tool like Fiddler to verify the url path of the policy xml file the client is looking for.
I have a C# .net webservice that I need to restrict access to. I already require my consumers to use a username and password to call the service. But, is there a way to restrict access to the actual asmx page and the WSDL? I would need to restrict access to the webservice by username/password and IP address. If a user did not have the correct credentials, I would not want them to know what webmethods exist in the webservice.
Can this be done though IIS? I know that I can restrict IP addresses through IIS, but can I also use usernames/passwords?
Is there any other way to do this outside of IIS, maybe using C#.net?
Well, since it's ASMX you have the entire ASP.NET runtime stack at your disposal.
Step #1 - managing the resource through .config
Apply a <location> tag for the resources you want secured. Assuming it's a single ASMX file you can simply do the following in your web.config:
<location path="MyWebService.asmx">
<system.web>
<!-- resource specific options will go here -->
</system.web>
</location>
Step #2 - authenticating your users
You need to decide how you're actually going to authenticate users. There are several ways to do this and several authentication standards you could leverage. You need to pick the approach that's the right fit for you.
If you're on an intranet and are using Windows authentication I would highly suggest leveraging that because it's truly the simplest option to get setup. However, if your services are being accessed over the internet then Windows authenticatio is not really an option and you need to choose from a web standard. The simplest of those is Basic Authentication, but you should only use this over SSL since the username/password are not encrypted (only base64 encoded). The next step up from that is Digest authentication which doesn't require SSL because the username/password are sent using an MD5 hash. For the ultimate you can go with SSL v3 where you issue a specific client certificate to each user of your API.
Now, which option you select for security dictates what else needs to be done. If you choose Windows security, it's as easy as adding the following element to the <system.web> element we started with in Step #1:
<authentication mode="Windows" />
The remainder of the security protocols are going to require a little more work. ASP.NET doesn't provide intrinsic support for Basic, Digest or SSL v3. Technically you can leverage IIS to do this type of authentication for you, but it's always going to map to a Windows user. If that's an option for you, then simply leave the <authentication mode="Windows" /> element and configure IIS accordingly. If, however, that is not an option, either because you simply have no control over IIS/ActiveDirectory or you need to authenticate against a custom user database, then that means that you need to hook up a custom HttpModule to provide support for these security protocols.
Step #3 - securing the resource
The simplest approach to securing the resource is to basically say: "don't let anyone who hasn't successfully authenticated in some way into this resource". This is done using the following authorization configuration:
<authorization>
<deny users="?" />
</authorization>
If you wanted to only allow certain users you could change to do the following instead:
<authorization>
<deny users="*" />
<allow users="jdoe, msmith" />
</authorization>
Another approach is to define roles (groups) and simply lock the resource down to a special role which you put the users who you want to access the resource into.
<authorization>
<deny users="*" />
<allow roles="My Service Users" />
</authorization>
This maps well to Windows authentication because you can just setup a Windows group and let your MIS team manage which users are in that group using ActiveDirectory. However, the feature also works just fine for non-Windows authentication assuming the security implementation you've used exposes roles via its IPrincipal implementation.
I don't know how practical this is for you, but you could consider upgrading to WCF. WCF is fully backward compatible with ASMX web services, and lets you control whether or not the WSDL is exposed by defining a MEX (metadata exchange) endpoint. No MEX endpoint, no WSDL.
You can stop WSDL being shown by removing the Documentation protocol from the element in Machine.config
Update:
Web Services authentication - best practices?
If your users have usernames/passwords you can use HTTP basic authentication via HTTPS.
You can also implement it in a slightly differnt way. The first call to your web service should be the authentication method. Client authenticates and receives an authentication token. This token should be presented to all other methods exposed by your web service.
Two options: Create an entirely different site on a different port with locked down permissions. This has the advantage of providing some amount of "security through obscurity" (half joking...) Or you can add a new Application under your site(same port, different path), on a different app pool and assign permissions that way.
In either case, your web service isn't going to be able to talk with the various ASP.NET "things" like the application object (well it will, but it won't be the same one). Deployment is only slightly harder: deploy the same binaries, but only include the one web service file.
You can authenticate using an HttpModule.
SSL + BasicAuthentication should yield the best interop with other tool chains.
In the HttpModule, you have access to the request and can deny unauthenticated users access to just .asmx requests. And even then you might let them access the WSDL.
Add <add path="*.asmx" verb="*" type="System.Web.HttpForbiddenHandler" validate="True" /> to the <httpHandlers> section of the web.config file