I have a simple WSDL for a webservice. With wsimport I generated the java wrappers. And I have implemented the generated interface in a class "MyService". Then I publish this webservice with the built-in features of Java6:
MyService myService = new MyService();
Endpoint endpoint = Endpoint.publish("http://localhost:80/servicetest/services/MyServiceINSoap", myService);
When I let this code run, everything works perfect - I am able to connect to the service with a soapclient and can execute the methods.
Now I want the built-in webserver of the javavm to use basic authentication - so the client has to provide an userid and a password. How do I accomplish this? Is this possible? Or do I need an application server (tomcat, jboss, whatever...)?
I have searched for some time but only found solutions for webservice which are hosted in an application server.
Many thanks in advance!
erwrock
As I found your answer I was quite relieved because I searched hours for a solution. But as I tried to follow your link I noticed that the page is not available any longer. Fortunately, I found the old version with the help of the Wayback Machine (https://archive.org/web/). Although, this article is great I had some problems with getting the basic auth to work at the client side. In the end I got it working with the help of java.net.Authenticator. Here are the code snippets which I hope to be useful for others.
Server:
javax.xml.ws.Endpoint serverEndpoint = Endpoint.create(new MyService());
com.sun.net.httpserver.HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
com.sun.net.httpserver.HttpContext httpContext = server.createContext("/myservice");
server.start();
AuthenticatorServer authenticatorServer = new AuthenticatorServer("myRealm", "myName", "myPwd");
httpContext.setAuthenticator(authenticatorServer);
serverEndpoint.publish(httpContext);
Where AuthenticatorServer is:
private static class AuthenticatorServer extends com.sun.net.httpserver.BasicAuthenticator {
private final String user;
private final String pwd;
public AuthenticatorServer(String realm, String user, String pwd) {
super(realm);
this.user = user;
this.pwd = pwd;
}
#Override
public boolean checkCredentials(String userNameInput, String passwordInput) {
return StringUtils.equals(user, userNameInput) && StringUtils.equals(pwd, passwordInput);
}
}
And on the Client side:
AuthenticatorClient authenticatorClient = new AuthenticatorClient("myName", "myPwd");
Authenticator.setDefault(authenticatorClient);
javax.xml.namespace.QName qName = new QName(namespaceURI, WS_SERVICE_NAME);
java.net.URL wsdlAddress = new URL(namespaceURI + WS_SERVICE_NAME + "?wsdl");
MyService service =(Service.create(wsdlAddress, qName)).getPort(MyService.class);
Where AuthenticatorClient is:
private static class AuthenticatorClient extends java.net.Authenticator {
private final String user;
private final String pwd;
public AuthenticatorClient(String user, String pwd) {
this.user = user;
this.pwd = pwd;
}
#Override
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication(user, pwd == null ? null : pwd.toCharArray()));
}
}
Found a solution here:
https://today.java.net/pub/a/today/2007/07/03/jax-ws-web-services-without-ee-containers.html
after hours of trial-and-error finally the right searchwords in google :)
Related
I want to consume a SOAP Web service which requires an OAuth2 authentication with client_credentials grant type.
From the documentation (http://cxf.apache.org/docs/jax-rs-oauth2.html#JAX-RSOAuth2-AdvancedOAuth2clientapplications) , I have found the BearerAuthSupplier which could be usefull. So I tried
#Bean
public CustomName customName()
{
final JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();
factoryBean.setServiceClass(CustomName.class);
factoryBean.setAddress("");
final CustomName serviceClient = (CustomName ) factoryBean.create();
// Get the underlying Client object from the proxy object of service interface
final org.apache.cxf.endpoint.Client proxy = ClientProxy.getClient(serviceClient);
final HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
final BearerAuthSupplier supplier = new BearerAuthSupplier();
supplier.setAccessTokenServiceUri("");
supplier.setConsumer(new Consumer("client-id", "client-secret"));
supplier.setRefreshEarly(true);
conduit.setAuthSupplier(supplier);
return serviceClient;
}
In the Authorization Header I had a Basic assertion (I wanted a Bearer). Plus, I had no possibility to set the scope of the token. I think there is something I missed ...
To get this working, I had to extend BearerAuthSupplier to somethink like this
public class CustomAuthSupplier extends BearerAuthSupplier {
private String accessTokenServiceUri;
public String getAuthorization(AuthorizationPolicy authPolicy,
URI currentURI,
Message message,
String fullHeader) {
ClientCredentialsGrant clientCredentialsGrant = new ClientCredentialsGrant("scope_needed");
clientCredentialsGrant.setClientId(this.getConsumer().getClientId());
clientCredentialsGrant.setClientSecret(this.getConsumer().getClientSecret());
WebClient wc = WebClient.create(this.accessTokenServiceUri, Collections.singletonList(new OAuthJSONProvider()));
ClientAccessToken at = OAuthClientUtils.getAccessToken(wc,clientCredentialsGrant);
this.setClientAccessToken(at);
return super.getAuthorization(authPolicy, currentURI, message, fullHeader);
}
public void setAccessTokenServiceUri(String uri) {
this.accessTokenServiceUri = uri;
super.setAccessTokenServiceUri(uri);
}
So far it works well, but I find it a bit complicated (and I'm not really sure of what i am doing). My question is : How to perform client credential grant with CXF when calling a Soap WS ?
I'm building a 3rd party app to authenticate with Contact Center Express. The documentation is necessary, but insufficient to accomplish this. For example,
https://developer.cisco.com/docs/contact-center-express/#!cisco-identity-service-client-sdk-guide/during-agent-login
// Get Access Token for the received Authorization Code
String redirectURI = config.getRedirectUri();
AccessToken token = client.getAccessToken(authCode, redirectURI);
When and where do you redirect the user to Contact Center to authenticate? I observed that Finesse will redirect the user to
https://contactcenter.example.com:8553/ids/v1/oauth/authorize?redirect_uri=https%3A%2F%2Ffinesse.example.com%3A443%2Fdesktop%2Fsso%2Fauthcode&client_id=8a75xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&state=aHR0cHM6Ly92bS1mLWZpbi1hLmRldi5pbi5zcGluc2NpLmNvbS9kZXNrdG9wL2pfaWRlbnRpdHlfY2hlY2s%2FZXJyb3I9dHJ1ZQlhcHBsb2dpbg%3D%3D&response_type=code
But where is it specified to use the identity service (IDS) path /ids/v1/oauth/authorize? And is state a required parameter? And does the IDS SDK handle the callback path /desktop/sso/authcode? I imagine that it doesn't but what are the parameters that will be sent to it? I'm using Spring framework.
Am I to reverse engineer the whole process, or is there additional documentation that I am missing?
Even after I receive an OAuth token, how would I use it to make other REST calls to other Cisco products? The Finesse REST APIs only mention HTTP basic authentication. There is no mention of headers for "Authorization: Bearer" tokens.
https://developer.cisco.com/docs/finesse/#!sign-in-to-finesse/sign-in-to-finesse
I had to reverse engineer it following all the redirects.
#Controller
public class SSOController {
#Autowired
private IdSClientConfigurationImpl config;
#Autowired
private IdSClient client;
#PostMapping("/login")
public String login(#RequestParam(name="user", required=true) String user) {
// redirect the user to the Cisco Contact Center Express Identity Service
String redirectURI = config.getRedirectUri();
String clientId = config.getClientId();
URI uri = UriComponentsBuilder
.fromUriString("https://contact-center-express:8553/ids/v1/oauth/authorize")
.queryParam("redirect_uri", "{redirect_uri}")
.queryParam("client_id", "{client_id}")
// .queryParam("state", "{state}") // base64 encoded
.queryParam("response_type", "code")
.build(redirectURI, clientId);
return "redirect:"+uri.toString();
}
#GetMapping("/idscallback")
public String idscallback(
#RequestParam(name="code", required=true) String code,
#RequestParam(name="state", required=false) String state,
HttpSession session) throws IdSClientException {
// Get Access Token for the received Authorization Code
String redirectURI = config.getRedirectUri();
AccessToken token = client.getAccessToken(code, redirectURI); // why do I need redirectURI when it's already redirected?
String accessTokenString = token.getAccess_token();
session.setAttribute("token", accessTokenString);
// model.addAttribute("token", accessTokenString);
return "redirect:/";
}
And in a bean far, far away...
#Bean
public IdSClientConfigurationImpl config() throws IOException, IdSClientException {
ClassPathResource idsclientResource = new ClassPathResource("idsclient.properties");
IdSClientConfigurationImpl config = new IdSClientConfigurationImpl(idsclientResource.getFile().getPath());
// IdSClientConfigurationImpl config = new IdSClientConfigurationImpl("src/main/resources/idsclient.properties");
config.load();
return config;
}
#Bean
public IdSClient setupIdsClient() throws IOException, IdSClientException {
IdSClient client = IdSClientFactory.getIdSClient();
client.setTLSContext(createSSLTrustManager(), createHostnameVerifier());
// client.setTLSContext(arg0, arg1) // use secure trust manager and hostname verifier in production
client.init(config);
return client;
}
private X509TrustManager createSSLTrustManager() {
X509TrustManager tm = new TrustAllX509TrustManager();
return tm;
}
private HostnameVerifier createHostnameVerifier() {
HostnameVerifier hv = new SkipAllHostNameVerifier();
return hv;
}
I'm building a web service that's supposed to register on another server by sending its wsdl URL to that server.
I built a very basic web service in Netbeans,
#WebService
public class RegisterTest{
#WebMethod(operationName = "emphasize")
public String emphasize(#WebParam(name = "inputStr") String input){
return input + "!!!";
}
}
and Netbeans automatically directs me to localhost:8080/RegisterTest/RegisterTestService?Tester, and naturally, the wsdl can be found at localhost:8080/RegisterTest/RegisterTestService?wsdl.
How would I programmatically get this URL?
Edit:
I've noticed that the only place that seems to store this URL is the glassfish server itself. The context-root seems to only be found in glassfish/domain//config/domain.xml.
Is there a nice way of accessing the glassfish server APIs? I can easily get the endpoint address through the UI in applications > serviceName > View Endpoint, is there a programmatic way of doing this?
I've tried looking through asadmin commands, but can't seem to find anything there that gets the context-root or the endpoint URL either.
Untested, but should be pretty close to what you're looking for:
#WebService
public class RegisterTest
{
#Resource
private WebServiceContext context;
#WebMethod(operationName = "emphasize")
public String emphasize(#WebParam(name = "inputStr") String input)
{
return input + "!!!";
}
#WebMethod(operationName = "getWsdlUrl")
public String getWsdlUrl()
{
final ServletContext sContext = (ServletContext)
this.context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
final HttpServletRequest req = (HttpServletRequest)
this.context.getMessageContext().get(MessageContext.SERVLET_REQUEST);
final StringBuilder sb = new StringBuilder();
sb.append(req.isSecure() ? "https" : "http");
sb.append("://");
sb.append(req.getLocalName());
if ((req.isSecure() && req.getLocalPort() != 443) ||
(!req.isSecure() && req.getLocalPort() != 80))
{
sb.append(":");
sb.append(req.getLocalPort());
}
sb.append(sContext.getContextPath());
sb.append(RegisterTest.class.getSimpleName());
sb.append("Service?wsdl");
return sb.toString();
}
}
Im new to Rest web services and say Ive created this web service using Netbeans
#Path("browse")
#Stateless
public class ArticleBrowseResource {
#EJB
private ArticleSearcherLocal ejbRef;
#GET
#Produces(MediaType.APPLICATION_XML)
public List<Article> browse(#DefaultValue("") #QueryParam("username") String username,#QueryParam("sd") String sd) {
// convert sd string to date
List<Article> articles = ejbRef.search(username, date);
return articles;
}
}
where Article is an entity which is anotated with #XmlRootElement
Now how am I supossed to retreive this list of articles in my client which for simplicity lets just say it is a java standard application? In SOAP web services I know that these objects are automatically generated but not in Rest.
This is the client class generated for this service by Netbeans
public class ArticleBrowseClient {
private WebResource webResource;
private Client client;
private static final String BASE_URI = "http://localhost:8080/cityblog/rest";
public ArticleBrowseClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
client = Client.create(config);
webResource = client.resource(BASE_URI).path("browse");
}
public <T> T browse(Class<T> responseType, String username, String sd) throws UniformInterfaceException {
WebResource resource = webResource;
if (username != null) {
resource = resource.queryParam("username", username);
}
if (sd != null) {
resource = resource.queryParam("sd", sd);
}
return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
public void close() {
client.destroy();
}
}
What is the best and simplest way to resolve this issue?
Any help is appreciated and
thx in advance
Please try fewer code generation and more understanding of what you are actually doing. On the server, you generate a XML message with help of JAXB. On the client side, you can consume this XML with a programming language and library you like. Just use tools like curl to see what is going actually over "the wire". Your generated client site looks fully reasonable. You just need your Article class from the server side on the client side. The generated code uses Jersey which can read XML messages per JAXB per default. So just drop your server side Article class in your client side classpath and use it. But please also have a look at the wire level protocol to understand the portability of your REST API.
Please, at least pseudo (but from working environment not "maybe this should work") application context and controller/filter that will authenticate and/or auto-register Facebook users.
This link: http://blog.kadirpekel.com/2009/11/09/facebook-connect-integration-with-spring-security/ will not do. Actually I will put minus point to anyone who will post it as answer. I spend 2 hours with the thing and I didn't get it to work. I ended bit more bolder and feeling more stupid than usual after this endeavor :-(
I would really like to see OAuth 2.0 solution for facebook connect. And restrict the use of Facebook JavaScript API to absolute minimum.
Following link shows about what I need:
http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/
Please post only code to this question. I already got all the advice I can handle.
UPDATE
I have servlet solution and posted answer here if anyone is interested:
Facebook Connect example in JSP (tomcat)
Here's an MVC implementation of facebook OAuth 2.0
The code's in C# and hopefully its similarity with java helps you out.
Controller(Entry point):Controller(in MVC) is the point in the code where the control reaches after someone clicks on the login link.
public ActionResult Authenticate()
{
var oauthFacebook = new FacebookOAuth();
if (Request["code"] == null)
{
//Redirect the user to Facebook for authorization.
Response.Redirect(oauthFacebook.AuthorizationLinkGet());
}
else
{
//Get the access token and secret.
oauthFacebook.AccessTokenGet(Request["code"]);
if (oauthFacebook.Token.Length > 0)
{
//We can now make our api calls
var user = oauthFacebook.GetAttributes();
}
}
}
FacebookOAuth Class
public class FacebookOAuth : Oauth
{
public FacebookOAuth()
{
Authorize = "https://graph.facebook.com/oauth/authorize";
AccessToken = "https://graph.facebook.com/oauth/access_token";
CallbackUrl = "http://<YourURLHere>/Authenticate";
AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
Provider = "Facebook";
}
public override string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
Authorize, ConsumerKey, CallbackUrl);
}
public User GetAttributes()
{
string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
return new User()
{
FirstName = FacebookUser.first_name,
MiddleName = FacebookUser.middle_name,
LastName = FacebookUser.last_name,
Locale = FacebookUser.locale,
UserEmail = FacebookUser.email,
AuthProvider = Provider,
AuthToken=Token
};
}
}
OAuth baseclass(Class from which FacebookOAuth derives)
public abstract class Oauth
{
#region Method enum
public enum Method
{
Get,
Post,
Delete
} ;
#endregion
protected string AccessToken;
protected string AttributesBaseUrl;
protected string Authorize;
protected string CallbackUrl;
protected string ConsumerKey;
protected string ConsumerSecret;
public string Provider { get; protected set; }
public string Token { get; set; }
public virtual string AuthorizationLinkGet()
{
return
string.Format(
"{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
Authorize, ConsumerKey, CallbackUrl);
}
public void AccessTokenGet(string authToken)
{
Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
Token = qs["access_token"];
}
}
}
public string WebRequest(Method method, string url, string postData)
{
StreamWriter requestWriter;
string responseData = string.Empty;
var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
if (webRequest != null)
{
webRequest.Method = method.ToString();
webRequest.ServicePoint.Expect100Continue = false;
webRequest.Timeout = 20000;
if (method == Method.Post)
{
webRequest.ContentType = "application/x-www-form-urlencoded";
//POST the data.
requestWriter = new StreamWriter(webRequest.GetRequestStream());
try
{
requestWriter.Write(postData);
}
finally
{
requestWriter.Close();
}
}
responseData = WebResponseGet(webRequest);
}
return responseData;
}
public string WebResponseGet(HttpWebRequest webRequest)
{
StreamReader responseReader = null;
string responseData;
try
{
responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
responseData = responseReader.ReadToEnd();
}
finally
{
if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
if (responseReader != null) responseReader.Close();
}
return responseData;
}
}
I actually just finished my non-javascript, implementation of the Facebook Graph API Authentication last night. I was a gargantuan pain in the a**, but it works and it's working fairly well.
I used the example from the link you posted above as a starting point, as well as, the code from here as a starting point. I had to write my own implementation of their FacebookGraphAuthenticationProvider and their FacebookGraphAuthenticationFilter, but now it works the way I want it to.
You need to create implementations of both of these files, put your filter in the filter chain, and create a implementation of the Spring Security UserDetailsService that the Provider can use to manage your user account information. I have some code on my machine at home that I can send you via email if you like.
Here are the steps I had to use to get the authentication to work:
Get an "code" for a user, this is done by making the following call: https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream (The scope is all the permissions you want to request from FB). This call will create an "authentication code" which will then be sent back to your "redirect_uri" (which I stated as http://{my fb app registered domain}/j_spring_security_authentication_check.
Once you have this "code", you need to make a call within your AuthenticationProvider that will retrieve an access_token for your user's session: this URL looks like: https://graph.facebook.com/oauth/access_token? client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE. You have to make sure your "redirect_uri" is the same as the one you did in #1. You'll make the above call using something like Apache's HttpClient, or the like.
Now with this access_token (which comes in the body of above response), you can get your user's profile information with the following URL: https://graph.facebook.com/me?access_token={ACCESS_TOKEN from above). The response will be in JSON. You can also use the access_token with all of the graph API to post status, pictures, etc.
I have some code at home that has my full implementation that I would be happy to share.
I hope this helps at least a bit. I suggest using the Spring Social app to get started with posting status, pictures, wall stuff, etc. This will be a good place to start looking at FB-Spring interaction.