WSO2 API Manager and Kerberos - wso2

I have set up a new WSO2 API Manager server (Version 2.6.0) and try to configure the server to support Kerberos but I have a problem of understanding the overall process.
Our client is an Angular application running on windows machines (Chrome or IE). In the documentation I found the sentence, The application should request a new access token by calling
curl -v -X POST -H "Authorization: Basic <base64 encoded client id:client secret value>" -k -d "grant_type=kerberos&kerberos_realm=<kerberos realm>&kerberos_token=**<kerberos token>**" -H "Content-Type:application/x-www-form-urlencoded" https://localhost:9443/oauth2/token
but where should this "kerberos token" should come from and how can I test it?
I have installed and configured the server corresponding to the documentation.
I have a service principal in the AD and configured the Identity provider in WSO2 API.
I have configured an example API which works with normal OAuth2
I have activated Kerberos on the application (WSO2 API Store)
My expected result would be, the service is called, the user is authenticated and the user info is passed to the backend service but at the moment I stack and cannot find a solution how I can find this kerberos tocken.

define authorized header as X-APIM-Auth when creating the API.
Build the custom handler code below, and copy the resulting jar to following directory in path /repository/components/dropins.
https://github.com/AndreaNim/kerberos-delegation-handler
You can add this custom handler to API and add the below logic to /repository/resources/api_templates/velocity_template.xml file.
configure the SPN of the IIS backend service as the targetSPN property in the handler as below,
<handler class="org.wso2.apim.kerberos.handler.CustomKerberosDelegationHandler">
<property name="targetSPN" value="<Server Principal Name>"/>
</handler>
Create a directory called “kerberos” inside /repository/conf/security/ folder and add the following files,
krb5.conf
login.conf
keytab
Sample krb5.conf file:
[libdefaults]
default_realm = EXAMPLE.COM
[realms]
EXAMPLE.COM = {
kdc = kdc1.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
Sample login.conf file:
KrbLogin {
com.sun.security.auth.module.Krb5LoginModule required
useTicketCache=false
refreshKrb5Config=true
doNotPrompt=true
useKeyTab=true
debug=true
storeKey=true
principal="< principal >"
keyTab="< keytab_path >";
};
Command to create a Keytab
ktpass /out <keytab> /princ HTTP/<FQDN>#<DOMAIN NAME> /mapuser <User Name of the AD account>/pass <User Password of the Authentication Service AD account> /crypto All /ptype KRB5_NT_PRINCIPAL
try to get the access token via password grant type.

Related

How to setup Postman to handle APIs from remote server

I have my django server running in a ssh client (ubuntu) but I want to test the api's in the local window machine. How could I achieve that?
If your web application is hosted ( have domain name like
http://www.stackoverflow.com) use the url in your postman.
If your webapp not yet deployed in some webserver ( apacahe, nginx+gunicorn, etc)
run the django application publicly in the server IP as follows
python manage.py runserver 0.0.0.0:8000 // make sure port 8000 is open or use an open port.
Also find the IP address of your ubuntu using the following command ( in the shell)
ifconfig
Use the ip-address you got in the postman (windows)
eg: if the IP address got is 90.101.111.25,
API endpoint: api/user/
method : POST
In postman client
use the url: 90.101.111.25/api/user/
select method : POST
Next you need to provide the Authorization ( to make sure only guanine users access your API).
Choose Authorization tab in postman, and select the Authorization (
Digest Auth, Basic, Token) your web app supports.
If you go with Token Authentication, find the the token for the (one of the )user created, and use it in postman.
Select Headers and add the following
key: Authorization
value: Token:<space>the-token-generated-by-django-in-the-db
Check the following to implement token based authentication in django( django-rest).
https://www.django-rest-framework.org/api-guide/authentication/

How to pass CKAN API authorization token via the WSO2-API Manager

I am using WSO2 API Manager (version 3.0.1) as front-end for accessing data via an API call to CKAN (version 2.8.2).
A private CKAN data set requires an authorization token as described here.
"When calling an API function that requires authorization, you must authenticate yourself by providing your API key with your HTTP request."
How is this accomplished in WSO2? Specifically, what configuration files/settings need to change to make this happen?
I see from this documentation that if configured in Eclipse using a tooling plug-in it can be accomplished with something like this (Step 23):
curl -k -H "Authorization: Bearer api-key-for-WSO2-goes-here" -H "Custom: Bearer api-key-for-CKAN-goes-here" https://my-wso2-host-goes-here:8243/test/1.0.0
However, these instructions require using Eclipse. But how can this be accomplished without Eclipse? I.e. what configuration files/settings need to be modified on the server or in the WSO2 API Publisher and/or the WSO2 API Dev Portal to pass the authorization token for CKAN through WSO2 API-M?
You do not have to use Eclipse for this. In the tutorial Eclispse plugin is used as a tool to generate the sequence easily. In that tutorial we needed a sequence
in the first place because the authorization header required by the backend is "Authorization". In WSO2 APIM this is a reserved header to pass the internally generated token. Therefore we first pass the backend token in a custom header with a different header name and then copy this value to Authorization header in the in-sequence.
The sequence would look like below.
<sequence xmlns="http://ws.apache.org/ns/synapse" name="authorization_header_exchange">
<property name="X-Authorization" expression="get-property('transport', 'X-Authorization')" scope="default" type="STRING"/>
<property name="Authorization" expression="get-property('X-Authorization')" scope="transport" type="STRING" description=""/>
<property name="X-Authorization" scope="transport" action="remove"/>
Refer [1] for more info.
However in your case you can send the api key in X-CKAN-API-Key along with the request itself without using a mediation sequence.
[1]. https://docs.wso2.com/display/APICloud/Sample+Mediation+Sequences#SampleMediationSequences-Passinganauthorizationheadertoyourbackend
I'm answering my own question...
TLDR
The answer by #naoko above is correct: to pass CKAN authorization through WSO2 API-M include X-CKAN-API-Key as a header with a value set to your CKAN user's private CKAN API key.
Long Version
Pass the CKAN API key like this:
curl -k -H "Authorization: Bearer wso2-app-key-here" -H "X-CKAN-API-Key: ckan-authorization-key-here" https://myWso2DeveloperPortal.com:8243/daas/3.0.1/action/resource_show?id=resource-id-of-CKAN-dataset-here
(Use -k if the host has a self-signed https certificate)
Where...
wso2-app-key-here is the application key found in the WSO2 Developer Portal.
ckan-authorization-key-here is your user account's private key in CKAN. (It can be found on your user profile page in the CKAN UI.)
resource-id-of-CKAN-dataset-here is the resource id of the dataset you want to query.
The resource_show method in this example will return metadata for the given CKAN resource. Other CKAN methods are invoked in a similar manner.
This is all thanks to CKAN for having an alternative to passing the key in a header named Authorize. In the case of CKAN, the variable X-CKAN-API-Key can be used. And this can be easily passed as shown above.
Mea culpa for not catching that in the CKAN docs in the first place (It's right there in my very own screenshot above!)...had I read thoroughly it would have saved a SO post for better or worse;)
Had CKAN not provided the alternative with X-CKAN-API-Key then this can be accomplished in version 3.0.0 as described in these pages:
"Passing a Custom Authorization Token to the Backend"
https://apim.docs.wso2.com/en/latest/Learn/APIGateway/MessageMediation/passing-a-custom-authorization-token-to-the-backend/
FWIW, I actually tried that before trying the X-CKAN-API-Key solution and it didn't work. Maybe I was doing something wrong. But since the X-CKAN-API-Key solution works for me I'm calling it done.

WSO2 Identity Server - Log Error: Server is Not Picking up the Client Certificate

When testing the WSO2 identity server rel. 5.1 using the Travelocity tool, I see a number of error messages recorded in the log file, telling:
"Server is not picking up the client certificate. Mutual SSL authentication is notdone"
The message repeats every 3 minutes.
Where is the missing certificate stored that needs to be updated to connect the Travelocity to the WSO2 IdP without writing error logs? In the travelocity.jks store at the client side, I currently see an alias entry for localhost and another entry for the IDP.
I've raised the debug level at the log4j.properties to the values:
log4j.logger.org.wso2.carbon.user=DEBUG
log4j.logger.org.wso2.carbon.identity=DEBUG
log4j.logger.org.wso2.carbon.idp.mgt=DEBUG
This is actually not an error log. This is a debug log. If you removed the following debug level entry from the log4j.properties file you will not see this.
log4j.logger.org.wso2.carbon.identity=DEBUG
MutualSSLAuthenticator is a carbon authenticator which is shipped by default with WSO2 IS 5.1.0. This authenticator is by default enabled from the authenticators.xml file located at
IS_HOME/repository/conf/security/ directory. This is actually not getting invoked by the SAML authentication flow, or OpenID flow which you might be trying with the Travelocity sample application. But, the log gets printed as the framework checks if the authenticator is capable of handling the authentication.
This authenticator is used with the OOTB supported Workflow Management Feature [1], for server to server authentication.
You can also disable this authenticator by commenting out the below configuration at authenticators.xml file, and yet, authentication with Travelocity sample application will work successfully.
<Authenticator name="MutualSSLAuthenticator">
<Priority>5</Priority>
<Config>
<Parameter name="UsernameHeader">UserName</Parameter>
<Parameter name="WhiteListEnabled">false</Parameter>
<Parameter name="WhiteList">
</Config>
</Authenticator>
[1]https://docs.wso2.com/display/IS510/Workflow+Management

WSO2API Manager : Api Store Error: Error in getting new access token

I have updated WSO2 default SLL with the custom SSL certificate on my Production Server on which WSO2Api installed.
SSL issues have been fixed, but now I am getting error while re-generating access token
Logs
Caused by: org.wso2.carbon.apimgt.keymgt.APIKeyMgtException: Error in getting new accessToken
at org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService.renewAccessToken(APIKeyMgtSubscriberService.java:281)
... 45 more
Caused by: java.lang.RuntimeException: Failed : HTTP error code : 500
at org.wso2.carbon.apimgt.keymgt.service.APIKeyMgtSubscriberService.renewAccessToken(APIKeyMgtSubscriberService.java:252)
... 45 more
TID: [0] [AM] [2014-08-27 10:57:41,440] ERROR {org.wso2.carbon.apimgt.hostobjects.APIStoreHostObject} - Error in getting new accessToken {org.wso2.carbon.apimgt.hostobjects.APIStoreHostObject}
If APIManager runs with a port offset,you need to do addtional changes.
Change the endpoint ports defined in default APIs shipped with APIManager
Find all default APIs of the API Manager in /repository/deployment/server/synapse-configs/default/api folder. Those are Authorize API, Login API, Token API and Revoke API. Open each of them and change the address endpoint config included port value to match with offset value.The default address endpoint config is
"address uri="https://192.168.1.7:9443/oauth2/token".If the AM standalone pack running with port offset 2 change that config as
address uri="https://192.168.1.7:9445/oauth2/token"
What I did to fix the issue was to 1) add admin user inside ApiKeyValidaor in api-manager.xml also into admin user via management console and into user-mgt.xml; 2) Inside api-manager.xml:
Change the following:
https://${carbon.local.ip}:${mgt.transport.https.port}${carbon.context}/services/
to:
https://[FQDN_OF_HOST}:${mgt.transport.https.port}${carbon.context}/services/
Reason is my server certificate only recorded the domain name, not ip address.
My setup: Product: WSO2 AM 1.10.0 DB: MSSQL Security: SAML2 integrated with PingIdentity OS: Linux
Please also refer to this question:
wso2 am 1.10.0 API Store: "Error occurred while executing the action generateApplicationKey" with " Invalid credentials provided."
The error may be due to one of these two things:
Your admin password is not set for ApiKeyManager in api_manager.xml.
SSL is not set properly.

Authenticating a WS-Security UsernameToken against a GlassFish realm gives "Authentication refused"

I have a SOAP webservice declared using #WebService in an EJB subproject of an EAR running in GlassFish 3.1.1 using its bundled Metro runtime. It's been annotated with the usual #DeclareRoles and #RolesAllowed, on the class level.
I have a WSIT descriptor for authentication using a simple plaintext-password UsernameToken.
In the EAR's glassfish-application.xml, I specify the realm as the standard file realm that comes with GlassFish. To this realm I have added a user for testing, belonging to a specific group. This group is mapped to the role I specified in glassfish-ejb-jar.xml.
I also enabled the Security Manager in GlassFish, as well as auditing. I restarted the server after doing this.
I have generated a client and set the username and password in callback handlers. I log to make sure the credentials are indeed set. I have also tried to set the credentials like this:
Map<String, Object> requestContext = ((BindingProvider)port).getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "myUsername");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "myPassword");
When I call the service, I get this on the server:
INFO: SEC5046: Audit: Authentication refused for [myUsername].
INFO: SEC1201: Login failed for user: myUsername
SEVERE: WSS1408: UsernameToken Authentication Failed
SEVERE: WSITPVD0035: Error in Verifying Security in Inbound Message.
com.sun.xml.wss.impl.WssSoapFaultException: Authentication of Username Password Token Failed
at com.sun.xml.ws.security.opt.impl.util.SOAPUtil.newSOAPFaultException(SOAPUtil.java:158)
at com.sun.xml.ws.security.opt.impl.incoming.UsernameTokenHeader.validate(UsernameTokenHeader.java:164)
at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.handleSecurityHeader(SecurityRecipient.java:341)
at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.cacheHeaders(SecurityRecipient.java:275)
at com.sun.xml.ws.security.opt.impl.incoming.SecurityRecipient.validateMessage(SecurityRecipient.java:225)
at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.verifyInboundMessage(WSITServerAuthContext.java:586)
at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.validateRequest(WSITServerAuthContext.java:360)
at com.sun.xml.wss.provider.wsit.WSITServerAuthContext.validateRequest(WSITServerAuthContext.java:263)
at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.processRequest(CommonServerSecurityPipe.java:173)
at com.sun.enterprise.security.webservices.CommonServerSecurityPipe.process(CommonServerSecurityPipe.java:144)
at com.sun.xml.ws.api.pipe.helper.PipeAdapter.processRequest(PipeAdapter.java:119)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:641)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:314)
at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:608)
at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:259)
at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:162)
at org.glassfish.webservices.Ejb3MessageDispatcher.handlePost(Ejb3MessageDispatcher.java:120)
at org.glassfish.webservices.Ejb3MessageDispatcher.invoke(Ejb3MessageDispatcher.java:91)
at org.glassfish.webservices.EjbWebServiceServlet.dispatchToEjbEndpoint(EjbWebServiceServlet.java:200)
at org.glassfish.webservices.EjbWebServiceServlet.service(EjbWebServiceServlet.java:131)
(Rest is snipped away)
and I get this on the client:
Authentication of Username Password Token Failed
javax.xml.ws.soap.SOAPFaultException: Authentication of Username Password Token Failed
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:189)
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:189)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:122)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:140)
I then created a simple servlet/JSP project and added a security restriction on the realm. Authentication using the same user works in this case.
The WS-Security policy looks like this:
<ns1:Policy xmlns:ns1="http://schemas.xmlsoap.org/ws/2004/09/policy" wsu:Id="MyServicePortBindingPolicy">
<ns1:ExactlyOne>
<ns1:All>
<ns2:SupportingTokens xmlns:ns2="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<ns1:Policy>
<ns1:ExactlyOne>
<ns1:All>
<ns2:UsernameToken ns2:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<ns1:Policy>
<ns1:ExactlyOne>
<ns1:All>
<ns2:WssUsernameToken10 />
</ns1:All>
</ns1:ExactlyOne>
</ns1:Policy>
</ns2:UsernameToken>
</ns1:All>
</ns1:ExactlyOne>
</ns1:Policy>
</ns2:SupportingTokens>
<ns3:UsingAddressing xmlns:ns3="http://www.w3.org/2006/05/addressing/wsdl" />
</ns1:All>
</ns1:ExactlyOne>
</ns1:Policy>
What's going wrong here? Any suggestions highly appreciated.
This solved itself when I disabled my own homebaked programmatic authentication mechanism, which threw a disruptive exception. Can't believe that didn't strike me before.