Web Service Error – Permission issue
2009. December 19.
Tanulság: Ha linuxon fut az appserver/webserver akkor a bug keresése közben sose felejtsük ki a jogosultságokból adódó problémákat.
A sztori:
Résztvevők: Ubuntu Linux, Weblogic AppServer, Apache Weblogic plugin, és a csodálatos alkalmazásunk egy generált Web Service interface-szel.
A Probléma: Application maintanance és partial upgrade után az ügyfél Web Service Kliense a createProduct(Product product) WS methoddal nem működött. A findAllProduct() -tal viszont igen. A hibaüzenet a következő volt:
The remote server returned an unexpected response:
(400) Bad Request. ---> System.Net.WebException:
The remote server returned an error: (400) Bad Request..
1. Tesztelés saját klienssel: Kipróbáltam saját C# WS klienssel, és minden WS method tökéletesen működött. A saját és a kliens environmentjén egyaránt. Megírtam nekik, hogy frissítsék a WSDL file-t, generálják újra a WS Kliens Stub-ot, és próbálják újra.
2. Újrapróbálták. Nem ment.
3. Csináltam nekik példaprojectet. Ők visszaküldték az ő példájukat, ami tényleg nem működött. De csak a kliens environmentjén nem működött.
Az én C# kliensem a régi módszerrel Web Referenciaként importálta a WSDL file-t, míg az övéké Service Reference-ként. Egy ideig azt hittem, hogy a Service reference megvalósítás a hibás. De a mi env-ünkön ment…
4. Hozzáfogtam összehasonlítani a mi rendszerünket az ügyfélével. Minden tökéletesnek tűnt. A generált WSDL file megegyezett. A domain logig nem jutott el a kérés… Közben kiderült, hogy csak a paraméteres függvényhívások buknak el. Az Apache access logjában a következőt találtam:
Invalid URI in request (- SOAP message -)
GET /bridge_error.html HTTP/1.1
Ez még ok, mert nincs bridge_error.html bekonfigurálva. De mitől jön bridge error?
5. Az Apache Weblogic pluginon bekonfigoltuk a logozást. Ebből az derült ki, hogy “/tmp/_wl_proxy/”-ban lévő temp file-t nem tudja írni az apache mert nincs hozzá jogosultsága, ezért bukik el a request.
- Going to get the post data of size=2419 clength=0
- getWLFilePath: Complete File name =
[/tmp/_wl_proxy/_post_9929_0]
- Cannot open TEMP post file '/tmp/_wl_proxy/_post_9929_0'
for POST of 2419 bytes
- Redirecting the error response to the errorPage =
[/bridge_error.html]
- IO error reading client POST data; sys err#:
[13] sys err msg [Permission denied]
Az ok: Amikor az ügyfél rendszergazdája karbantarotta a servert, létrehozott egy új usert/groupot az Apache server futtatásához. Mivel az Apache ezzel az új userrel futott, az előzőleg létrehozott “_wl_proxy” könyvtárhoz nem volt hozzáférése. A POST HTTP requestek esetén az Apache proxy temp fileba menti a paramétereket, amiket jelen esetben nem tudott lementeni.
- Az ügyfél C# kliensével (Service Reference based) a paraméter nélküli függvényhívások azért működtek, mert nem kellett az Apache-nak semmit lementenie.
- Az én C# kliensemmel (Web Reference based) azért működött, mert az GET HTTP requesteket használt…
Megoldás: Rendszergazdaként töröltük a “_wl_proxy” mappát. A következő paraméteres HTTP POST requestnél az Apache újrakreálta ezt a mappát, és ezek után minden tökéletesen működött.
JAX-WS Kliens és a HTTP Authentikáció
2009. December 14.
Az előző post-hoz kapcsolódik a következő kis probléma:
Amikor a Maven JAX-WS Plugin-jának wsimport goal-jával legeneráltam a Kliens stub-ot, a Service URL-jét szerettem volna konfigurálhatóvá tenni. Fontos komment, hogy a WSDL file és a Service methodusai is csak egy basic HTTP authentikáció után érhetőek el.
Tehát elsőre fogtam magam, és a következőket követtem el:
URL url = new URL("http://localhost/ServiceUrl");
QName qName = new QName("ServiceNamespace", "ServiceName");
AuthWService authWService = new AuthWService(url, qName);
AuthWServicePort port = authWService.getAuthWServicePort();
És itt az történt, amire egyáltalán nem számítottam:
javax.xml.ws.WebServiceException Response: '401:
Unauthorized' for url: 'http://localhost/ServiceUrl'
Az AuthWService példányosításakor elszált a futtatás, mivel nem tudott hozzáférni a megadott URL-en az adott Service-hez. Merthogy nincs meg a username/password amire szükség lenne… De miért is akarja ő azt most még elérni? Ott van a WSDL file a resources mappában. Az URL valid. A Service class példányosításhoz miért kellene nekem rögtön elérnem magát a Service-t a net-en? Nem elég csak akkor amikor meg akarom hívni az egyik methodusát? Mindegy.
Rövid keresgélés után (thx google) a következőt találtam: megoldás
1. Authenticator:
Kell nekünk egy saját authenticator class, ami elintézi a username/password authentikációt, amikor ez a szemét váratlanul csatlakozni akar a net-en levő Service-hez. Ez a következőképpen nézhet ki:
public class HttpAuthenticator extends Authenticator {
private String userName;
private String password;
public HttpAuthenticator(String username, String password) {
this.userName = username;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
char[] pwdChar = password.toCharArray();
return new PasswordAuthentication(userName, pwdChar);
}
}
2. Beállítjuk a Default Authentikátort:
Mielőtt példányosítanánk az AuthWService classt, be kell állítanunk a Default Authenticatort a következőképpen:
Authenticator.setDefault(new HttpAuthenticator("UserName", "Password"));
Itt már majdnem készen vagyunk. Az AuthWService példányosodik, eddig minden rendben.
3. UserName és Password beállítása az AuthWServicePort objecten:
A port object-en meghívott Remote WS Method-oknak szintén szükségük van authentikációra. Ezt a port objecten tudjuk beállítani az alábbi példa alapján:
AuthWServicePort port = authWService.getAuthWServicePort();
((BindingProvider) port).getRequestContext().put(
BindingProvider.USERNAME_PROPERTY, "UserName");
((BindingProvider) port).getRequestContext().put(
BindingProvider.PASSWORD_PROPERTY, "Password");
Ezzel készen is vagyunk.
Megjegyzés: Ha a WSDL file-unk nincs HTTP Authentikációval védve, akkor az 1. és 2. pontra nincs szükségünk….
Újabb WS Project Eclipse-ben mavennal
2009. December 9.
I. Maven plugin Eclipse-hez: Én az m2eclipse plugint installáltam (http://m2eclipse.sonatype.org/)
II. Új Project: Hozzunk létre új Maven Projectet eclipse-ben:



- src/main/java: Csak a forráskódnak amit írunk.
- src/main/resources: Minden más resource (Nálunk pl.: a WSDL file és a konfig fileok is).
- src/test/java: JUnit tesztek
- src/resources: a tesztekhez szükséges resource-ok, amik nem lesznek deployolva…
- target: a fordítás eredménye kerül ide. (+ a resource fileok is)
III: Project Object Model: A pom.xml file irja le a teljes projectet. Szemben az ant-tal, ahol a build.xml file leírja a definiált projectünk elemein végzendő műveleteket (dependent lib-eket tesz a classpathra, fordít, könyvtárat hoz létre, jar/war file-t készít, deployol, stb.), a maven pom.xml-je a project gerincét adja. Itt határozzuk meg a project függőségeit, a pluginokat amelyeket a build sorén használni szeretnénk, a repository-kat amelyekből a különböző lib-eket letölti a Maven.
A Maven Project életciklusai:
- generate sources: pl.: A mi esetünkben a wsdl fileból generál Java forráskódot.
- compile: A forráskód fordítása.
- test-compile: A JUnit tesztek fordítása.
- test: A JUnit tesztek futtatása.
- package: jar, war stb.
- integration-test:deployol az staging environmentre ha szükséges.
- install:belepakolja a local repository-ba az elkészült jar/war filet, ha más projectek ezen dependálnak.
- deploy: production environmentre másolja fel a végleges verziót.
A mi pom xml fileunk a következőképpen néz ki:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>GAAuthWSTest</groupId> <artifactId>GAAuthWSTest</artifactId> <version>0.0.1-SNAPSHOT</version> </project>

<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>src/main/java</source> <source>src/main/generated</source> <source>src/main/resources</source> <source>src/test/java</source> </sources> </configuration> </execution> </executions> </plugin>
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <executions> <execution> <goals> <goal>wsimport</goal> </goals> </execution> </executions> <configuration> <wsdlUrls> <wsdlUrl>src/main/resources/AuthWService.wsdl</wsdlUrl> </wsdlUrls> <sourceDestDir>src/main/generated</sourceDestDir> <packageName>com.wk.auth.ws</packageName> </configuration> </plugin>
VII. Hibák, amikbe belefutottam:
-
Java verzió:A Java 1.6 update 4 előtti változatai a JAX-WS 2.0-át használják. Én a mavennel viszont a 2.1.3-as verziót töltöttem le. Probléma nem is látszott egészen addíg, amíg az Eclipse-ből nem akartam futtatni közvetlenül egy tesztet. Mivel ekkor az eclipse-ben beállított sun-os rt.jar-t kezdte használni a program, a maven által letöltött jaxws-rt.jar helyett. Java update-vel megoldódott.
-
RPC/Encoded wsdl file: Nincs rá megoldás. A JAX-WS nem támogatja…

