I´m trying to make an AngularJs web that sends login and password to an ASP.NET WebApi backend and login this user with Thinktecture.
I have Thinktecture working fine with other project, ASP.NET MVC, using WS-Federation. Now I´m trying to do something similar but changing some components and I can´t make it work.
How can I send from ASP.NET WebApi the userName and password to Thinktecture and get it validated?
using System.Collections.Generic;
using System.IdentityModel.Services;
using System.Web.Http;
using WebApi_AngularJs.Model;
namespace WebApi_AngularJs.Controllers
{
public class AuthorizationController : ApiController
{
// POST: api/Authorization
public LoginResponse Post([FromBody]Login data)
{
//HOW TO SEND data.user and data.password to ThinkTecture and get
//response if user valid or not??
var response = new LoginResponse { access_token = "token", data = "data"};
return response;
}
}
}
Thank you!
There are a few things you need to do. Create an OAuth client that will make token requests, and use that to get access tokens from identity server allowing you to access your web api endpoints. To do this your OAuth client needs to have implicit flow enabled. You then make a login request to Identity server, typically through a pop up window to allow your OAuth client to log in.
You need to pass in your OAuth client details in the query string of the login request to Idsrv, an OAuth client config would be what you defined in your Idsrv admin panel for the OAuth client, you would parameterize that and append it to the oauth2/authorzie url:
getIdpOauthEndpointUrl: function () {
return "https://192.168.1.9/issue/oauth2/authorize";
},
getOAuthConfig: function () {
return {
client_id: "Your Oauth CLient ID that you specifie din Identity Server",
scope: "The scope of your RP",
response_type: "token",
redirect_uri: "https://..YourAngularAppUrl/AuthCallback.html"
};
}
You then open the login window:
var url = authService.getIdpOauthEndpointUrl() + "?" + $.param(authService.getOAuthConfig());
window.open(url, "Login", "height=500,width=350");
In your OAuth client inIdsrv you need to specify a redirect URL, in our case:
https://YourAngularAppUrl/AuthCallback.html
that is what you pass in to the the login request to identity server along with you OAuth client details. The AuthCallback.html page does nothing but extract the access token returned by idsrv to that page in a query string, and passes that into your angular app, how you do that is up to you, but that access token needs to be put into your $http headers.
The access token can be extracted in your AuthCallback.html page like this:
<script src="/Scripts/jquery-2.0.3.js"></script>
<script src="/Scripts/jquery.ba-bbq.min.js"></script>
<script type="text/javascript">
var params = $.deparam.fragment(location.hash.substring(1));
window.opener.oAuthCallback(params);
window.close();
</script>
the OAuthCallback function is defined in my shell page, my index.html and is responsible for passing the token it's given into my angular app and putting it into the $http headers.
function oAuthCallback(OAUTHTOKEN) {
angular.element(window.document).scope().setHttpAuthHeaderAndAuthenticate(OAUTHTOKEN);
}
The setHttpAuthHeaderAndAuthenticate() function is defined on my $rootScope, and it puts the token into the $http authorizaiton headers:
$http.defaults.headers.common.Authorization = 'Bearer ' + OAUTHTOKEN["access_token"];
Have a look at this post by Christian Weyer It does exactly what we're doing, but it's a knockout/web-api app, same concept still.
The next step is to tell your web api to accept the the access token from idsrv, this is simple;
public static void Configure(HttpConfiguration config)
{
var authConfig = new AuthenticationConfiguration();
authConfig.AddJsonWebToken(
YourIdsrvSiteId, YourRpsScope/Relam,YourRpsSymmetricSigningKey
);
config.MessageHandlers.Add(new AuthenticationHandler(authNConfig));
}
You could also define a ClaimsAuthenticationManager and a ClaimsAuthorizationManager here to allow you to transform claims and Grant/Deny acces sto the web api resources. Again this is all covered in Christian Weyer's post. Hope this helps.
Finally, after reading a lot I have this:
In AngularJS:
'use strict';
app.factory('authService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) {
var serviceBase = 'http://localhost:64346/';
var authServiceFactory = {};
var _authData = localStorageService.get('authorizationData');
var _authentication = {
isAuth: _authData != null? true : false,
userName: _authData != null ? _authData.userName : ""
};
var _saveRegistration = function (registration) {
_logOut();
return $http.post(serviceBase + 'api/account/register', registration).then(function (response) {
return response;
});
};
var _login = function (loginData) {
var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
var deferred = $q.defer();
$http.post(serviceBase + 'api/authorization', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
_authentication.isAuth = true;
_authentication.userName = loginData.userName;
deferred.resolve(response);
}).error(function (err, status) {
_logOut();
deferred.reject(err);
});
return deferred.promise;
};
var _logOut = function () {
$http.delete(serviceBase + 'api/authorization').success(function() {
localStorageService.remove('authorizationData');
_authentication.isAuth = false;
_authentication.userName = "";
});
};
var _fillAuthData = function () {
var authData = localStorageService.get('authorizationData');
if (authData) {
_authentication.isAuth = true;
_authentication.userName = authData.userName;
}
}
authServiceFactory.saveRegistration = _saveRegistration;
authServiceFactory.login = _login;
authServiceFactory.logOut = _logOut;
authServiceFactory.fillAuthData = _fillAuthData;
authServiceFactory.authentication = _authentication;
return authServiceFactory;
}]);
In WebApi:
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Protocols.WSTrust;
using System.IdentityModel.Services;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.Web.Http;
using System.Xml;
using Thinktecture.IdentityModel.Constants;
using Thinktecture.IdentityModel.WSTrust;
using WebApi_AngularJs.Model;
namespace WebApi_AngularJs.Controllers
{
public class AuthorizationController : ApiController
{
// GET: api/Authorization
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/Authorization/5
[Authorize]
public string Get(int id)
{
return "value";
}
// POST: api/Authorization
public LoginResponse Post([FromBody]Login data)
{
var credentials = new ClientCredentials();
credentials.UserName.UserName = data.UserName;
credentials.UserName.Password = data.Password;
ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true;
var claims = GetClaimsFromIdentityServer(data.UserName, data.Password);
var response = new LoginResponse();
if (claims != null)
{
//All set so now create a SessionSecurityToken
var token = new SessionSecurityToken(claims)
{
IsReferenceMode = true //this is
//important.this is how you say create
//the token in reference mode meaning
//your session cookie will contain only a
//referenceid(which is very small) and
//all claims will be stored on the server
};
FederatedAuthentication.WSFederationAuthenticationModule.
SetPrincipalAndWriteSessionToken(token, true);
response = new LoginResponse { access_token = token.Id , data = "data"};
}
return response;
}
// PUT: api/Authorization/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Authorization/
public void Delete()
{
//clear local cookie
FederatedAuthentication.SessionAuthenticationModule.SignOut();
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
}
private ClaimsPrincipal GetClaimsFromIdentityServer(string username, string password)
{
const string WS_TRUST_END_POINT = "https://srv:4443/issue/wstrust/mixed/username";
var factory = new System.ServiceModel.Security.WSTrustChannelFactory
(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
string.Format(WS_TRUST_END_POINT));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = username;
factory.Credentials.UserName.Password = password;
var rst = new System.IdentityModel.Protocols.WSTrust.RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
TokenType = TokenTypes.Saml2TokenProfile11,
AppliesTo = new EndpointReference
("urn:webapisecurity")
};
var st = factory.CreateChannel().Issue(rst);
var token = st as GenericXmlSecurityToken;
var handlers = FederatedAuthentication.FederationConfiguration.
IdentityConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader
(new StringReader(token.TokenXml.OuterXml))) as Saml2SecurityToken;
var identity = handlers.ValidateToken(token).First();
var principal = new ClaimsPrincipal(identity);
return principal;
}
}
}
In Web.Config:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:FederationMetadataLocation" value="https://srv:4443/FederationMetadata/2007-06/FederationMetadata.xml" />
<add key="ida:Realm" value="urn:webapisecurity" />
<add key="ida:AudienceUri" value="urn:webapisecurity" />
<add key="AppName" value="Web API Security Sample" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules>
<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="urn:webapisecurity" />
</audienceUris>
<claimsAuthorizationManager type="Thinktecture.IdentityServer.Ofi.AuthorizationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
<claimsAuthenticationManager type="Thinktecture.IdentityServer.Ofi.AuthenticationManager, Thinktecture.IdentityServer.Ofi, Version=1.0.0.0, Culture=neutral" />
<certificateValidation certificateValidationMode="None" />
<issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<trustedIssuers>
<add thumbprint="489116B0FCF14DF66D47AE272C3B9FD867D0E050" />
</trustedIssuers>
</issuerNameRegistry>
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler requireSsl="false" />
<wsFederation passiveRedirectEnabled="true" issuer="https://srv:4443/issue/wsfed" realm="urn:webapisecurity" reply="http://localhost:64346/" requireHttps="false" />
</federationConfiguration>
</system.identityModel.services>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
With this, I can see FedAuth cookie set in browser and it makes validation in WebApi too.
Related
I have soap link like this http://example.com/index.php/api/v2_soap/?wsdl (it is a magento website), the username password is abc , 123
I just added a service reference at solution explorer the name is ServiceReference1
I created a button (using vs2015, project name is printOrder) as the code is following:
private void button1_Click(object sender, EventArgs e)
{
}
the app.config is the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Binding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://example.com/index.php/api/v2_soap/index/"
binding="basicHttpBinding" bindingConfiguration="Binding"
contract="ServiceReference1.PortType" name="Port" />
</client>
</system.serviceModel>
</configuration>
So,
1) how to create a soap client object with username and password?
2) after created soap client object, how do i call the web service?
i've searched a lot of topics in google but seems there is small different from my case......
Anyone know how to to that?
The same thing i want to do is
$cs = getSesstion();
$result = $cs['client']->salesOrderShipmentInfo($cs['session'], '200001811');
$complexFilter = array(
'complex_filter' => array(
array(
'key' => 'orderIncrementId',
'value' => array('key' => 'in', 'value' => '100004496')
)
)
);
var_dump($cs);
//$result = $cs['client']->salesOrderInfo($cs['session'],'100004496');
//var_dump($result);
function getSesstion() {
$client = new SoapClient('http://example.com/index.php/api/v2_soap/?wsdl');
$username = 'vtec';
$apikey= 'Abcd1234';
$session = $client->login($username, $apikey);
$cs = array();
$cs['client'] = $client;
$cs['session'] = $session;
return $cs;
}
----------------------------answer-----------------------------
with Regie Baquero's help, the right code i found is
ServiceReference1.PortTypeClient client = new ServiceReference1.PortTypeClient();
string session = client.login("vtec","Abcd1234");
Console.WriteLine(session);
//client.(session, "product_stock.list", "qqaz");
var result = client.salesOrderInfo(session, "145000037");
//client.endSession(session);
Console.WriteLine(result.increment_id.ToString());
If you have already added your soap service what you need is to declare it in your code something like:
`ServiceReference1.Service service variable = new ServiceReference1.Service();`
in order for you to access method or function inside the soap service.
Sample code if you have written your soap service in visual studio c# your code should look like this:
[WebMethod]
public bool Password_Verification(string password)
{
if(password=="12345")
{
return true;
}
}
you can access it using
`ServiceReference1.Service service variable = new ServiceReference1.Service();`
bool verify = service variable.Password_Verification("12345");
Same goes with wsdl file. you just need to know what function/method is implemented in that soap service.
.........................
I have a Single Page Application with a webClient and a webAPI. When I go to a view which has a table, my table is not being updated. Actually the API is only being called once upon startup of application even though it is suppose to be called each time, or what I expected to happen.
Service Code -
function getPagedResource(baseResource, pageIndex, pageSize) {
var resource = baseResource;
resource += (arguments.length == 3) ? buildPagingUri(pageIndex, pageSize) : '';
return $http.get(serviceBase + resource).then(function (response) {
var accounts = response.data;
extendAccounts(accounts);
return {
totalRecords: parseInt(response.headers('X-InlineCount')),
results: accounts
};
});
}
factory.getAccountsSummary = function (pageIndex, pageSize) {
return getPagedResource('getAccounts', pageIndex, pageSize);
};
API Controller -
[Route("getAccounts")]
[EnableQuery]
public HttpResponseMessage GetAccounts()
{
int totalRecords;
var accountsSummary = AccountRepository.GetAllAccounts(out totalRecords);
HttpContext.Current.Response.Headers.Add("X-InlineCount", totalRecords.ToString());
return Request.CreateResponse(HttpStatusCode.OK, accountsSummary);
}
I can trace it to the service, but it will not hit a break point in the controller.
I added this to my web.config file for the REST API project and now it works as I need it -
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
<!-- HTTP 1.1. -->
<add name="Pragma" value="no-cache" />
<!-- HTTP 1.0. -->
<add name="Expires" value="0" />
<!-- Proxies. -->
</customHeaders>
</httpProtocol>
</system.webServer>
Thanks everybody for pointing me in the right direction!
I suspect the REST service response is getting cached in your browser on first call. So on REST service side add headers in response not to cache it or in your request add some additional changeable parameter(like time stamp) to ensure browser will not pick up the response form cache.
I am having trouble getting my Camel route to successfully POST a message to an existing RESTful web service. I have tried all the examples in the camel cxf package but none of them produce a web service call (they are consumers). I would love to find a working example for this so I can step through the CxfRsProducer execution to hopefully discover why my route is not posting correctly to the web service.
Here is my RouteBuilder's configuration:
public void configure()
{
//errorHandler(deadLetterChannel(String.format("file:%s/../errors", sourceFolder)).useOriginalMessage().retriesExhaustedLogLevel(LoggingLevel.DEBUG));
errorHandler(loggingErrorHandler());
/*
* JMS to WS route for some of the events broadcast to the jms topic
*/
Endpoint eventTopic = getContext().getEndpoint(String.format("activemq:topic:%s?clientId=%s&durableSubscriptionName=%s", eventTopicName, durableClientId, durableSubscriptionName));
from(eventTopic) // listening on the jms topic
.process(eventProcessor) // translate event into a Notifications object (JAX-RS annotated class)
.choice() // gracefully end the route if there is no translator for the event type
.when(header("hasTranslator").isEqualTo(false)).stop() // no translator stops the route
.otherwise() // send the notification to the web service
.to("cxfrs:bean:rsClient");
}
Here is the rsClientBean:
<cxf:rsClient id="rsClient"
address="http://localhost/ws"
serviceClass="com.foo.notifications.NotificationsResource"
loggingFeatureEnabled="true" />
I'm pretty new to REST and I don't really understand what the serviceClass does for the rsClient because it looks to me like the definition of the exposed web service on the server.
The NotificationsResource class:
#Path("/notifications/")
public class NotificationManagerResource
{
// NOTE: The instance member variables will not be available to the
// Camel Exchange. They must be used as method parameters for them to
// be made available
#Context
private UriInfo uriInfo;
public NotificationManagerResource()
{
}
#POST
public Response postNotification(Notifications notifications)
{
return null;
}
}
The processor creates a Notifications object to put in the exechange message body:
private class EventProcessor implements Processor
{
#Override
public void process(Exchange exchange) throws Exception
{
Message in = exchange.getIn();
IEvent event = (IEvent) in.getBody();
Notifications notifications = null;
in.setHeader("hasTranslator", false);
in.setHeader("Content-Type", "application/xml");
in.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, false);
// I've tried using the HTTP API as 'true', and that results in a 405 error instead of the null ptr.
INotificationTranslator translator = findTranslator(event);
if (translator != null)
{
notifications = translator.build(event);
in.setHeader("hasTranslator", true);
}
// replace the IEvent in the body with the translation
in.setBody(notifications);
exchange.setOut(in);
}
}
The Notifications class is annotated with JAXB for serialization
#XmlRootElement(name = "ArrayOfnotification")
#XmlType
public class Notifications
{
private List<Notification> notifications = new ArrayList<>();
#XmlElement(name="notification")
public List<Notification> getNotifications()
{
return notifications;
}
public void setNotifications(List<Notification> notifications)
{
this.notifications = notifications;
}
public void addNotification(Notification notification)
{
this.notifications.add(notification);
}
}
The error that is returned from the web service:
Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
Id ID-PWY-EHANSEN-01-62376-1407805689371-0-50
ExchangePattern InOnly
Headers {breadcrumbId=ID:EHANSEN-01-62388-1407805714469-3:1:1:1:47, CamelCxfRsUsingHttpAPI=false, CamelRedelivered=false, CamelRedeliveryCounter=0, Content-Type=application/xml, hasTranslator=true, JMSCorrelationID=null, JMSDeliveryMode=2, JMSDestination=topic://SysManEvents, JMSExpiration=1407805812574, JMSMessageID=ID:EHANSEN-01-62388-1407805714469-3:1:1:1:47, JMSPriority=4, JMSRedelivered=false, JMSReplyTo=null, JMSTimestamp=1407805782574, JMSType=null, JMSXGroupID=null, JMSXUserID=null}
BodyType com.ehansen.notification.types.v2.Notifications
Body <?xml version="1.0" encoding="UTF-8"?><ArrayOfnotification xmlns="http://schemas.datacontract.org/2004/07/ehansen.Notifications.Dto"> <notification> <causeType>EVENT_NAME</causeType> <causeValue>DeviceEvent</causeValue> <details> <notificationDetail> <name>BUSY</name> <value>false</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>DESCRIPTION</name> <value>Software Computer UPS Unit</value> <unit>name</unit> </notificationDetail> <notificationDetail> <name>DEVICE_NUMBER</name> <value>1</value> <unit>number</unit> </notificationDetail> <notificationDetail> <name>DEVICE_SUB_TYPE</name> <value>1</value> <unit>type</unit> </notificationDetail> <notificationDetail> <name>DEVICE_TYPE</name> <value>UPS</value> <unit>type</unit> </notificationDetail> <notificationDetail> <name>FAULTED</name> <value>false</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>RESPONDING</name> <value>true</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>STORAGE_UNIT_NUMBER</name> <value>1</value> <unit>number</unit> </notificationDetail> </details> <sourceType>DEVICE_ID</sourceType> <sourceValue>1:UPS:1</sourceValue> <time>2014-08-11T18:09:42.571-07:00</time> </notification></ArrayOfnotification>
]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.NullPointerException
at java.lang.Class.searchMethods(Class.java:2670)
at java.lang.Class.getMethod0(Class.java:2694)
at java.lang.Class.getMethod(Class.java:1622)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.findRightMethod(CxfRsProducer.java:266)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.invokeProxyClient(CxfRsProducer.java:222)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.process(CxfRsProducer.java:90)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor$2.doInAsyncProducer(SendProcessor.java:143)
at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:307)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:138)
It is the methodName parameter in the following method from CxfRsProducer class that is null... so I assume there is something about my rsClient that is not configured correctly.
private Method findRightMethod(List<Class<?>> resourceClasses, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException {
Method answer = null;
for (Class<?> clazz : resourceClasses) {
try {
answer = clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
// keep looking
} catch (SecurityException ex) {
// keep looking
}
if (answer != null) {
return answer;
}
}
throw new NoSuchMethodException("Cannot find method with name: " + methodName + " having parameters: " + arrayToString(parameterTypes));
}
Thanks for any help anyone can provide!
The serviceClass is a JAX-RS annotated Java class that defines the operations of a REST web service.
When configuring a CXF REST client, you must specify and address and a serviceClass. By inspecting the annotations found on the serviceClass, the CXF client proxy knows which REST operations are supposed to be available on the REST service published on the specified address.
So in your case, you need to add in.setHeader.setHeader(CxfConstants.OPERATION_NAME, "postNotification"); to the EventProcessor to tell camel which method of the service class you want to call.
Alright then. Here is the camel configuration xml file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/cxf
http://camel.apache.org/schema/cxf/camel-cxf.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
>
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="helloBean" class="com.examples.camel.cxf.rest.resource.HelloWorldResource" />
<cxf:rsServer id="helloServer" address="/helloapp" loggingFeatureEnabled="true">
<cxf:serviceBeans>
<ref bean="helloBean" />
</cxf:serviceBeans>
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</cxf:providers>
</cxf:rsServer>
<camelContext id="context" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxfrs:bean:helloServer />
<log message="Processing CXF route....http method ${header.CamelHttpMethod}" />
<log message="Processing CXF route....path is ${header.CamelHttpPath}" />
<log message="Processing CXF route....body is ${body}" />
<choice>
<when>
<simple>${header.operationName} == 'sayHello'</simple>
<to uri="direct:invokeSayHello" />
</when>
<when>
<simple>${header.operationName} == 'greet'</simple>
<to uri="direct:invokeGreet" />
</when>
</choice>
</route>
<route id="invokeSayHello">
<from uri="direct:invokeSayHello" />
<bean ref="helloBean" method="sayHello" />
</route>
<route id="invokeGreet">
<from uri="direct:invokeGreet" />
<bean ref="helloBean" method="greet" />
</route>
</camelContext>
</beans>
The actual resource implementation class looks like below.
package com.examples.camel.cxf.rest.resource;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
public class HelloWorldResource implements HelloWorldIntf
{
public Response greet() {
return Response.status(Status.OK).
entity("Hi There!!").
build();
}
public Response sayHello(String input) {
Hello hello = new Hello();
hello.setHello("Hello");
hello.setName("Default User");
if(input != null)
hello.setName(input);
return Response.
status(Status.OK).
entity(hello).
build();
}
}
class Hello {
private String hello;
private String name;
public String getHello() { return hello; }
public void setHello(String hello) { this.hello = hello; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
You don't need , and cxf:rsServer> to be provided.
The tag alone will suffice to handle a web service request and invoke a route.
In case you have both and the then invoking the former will not help you in executing a route. For a route to get invoked, the request must reach to the address published by .
Hope this helps.
I am trying to do "SAML 2.0 Bearer Assertion for SalesForce"
I am getting {"error":"invalid_grant","error_description":"invalid assertion"}
Is there any way to validate bearer assertion at salesforce?
I did following in my code
String environment = "https://login.salesforce.com/services/oauth2/token?saml=MgoTx78aEPRbRaz0CkRqjaqrhP3sCa7w7.Y5wbrpGMNT07zKRYwcNWf0zs";
Map<String, String> map = new HashMap<String, String>();
HttpClient httpclient = new HttpClient();
PostMethod post = new PostMethod(environment);
post.addParameter("grant_type", "urn:ietf:params:oauth:grant-type:saml2-bearer");
post.addParameter("client_assertion", Base64.encode(samlResponse.getBytes()));
post.addParameter("client_assertion_type","urn:ietf:params:oauth:client_assertion_type:saml2-bearer");
post.addParameter("format", "json");
String accessToken= null;
String instanceUrl = null;
try {
httpclient.executeMethod(post);
JSONObject authResponse = new JSONObject(new JSONTokener(new InputStreamReader(post.getResponseBodyAsStream())));
System.out.println(authResponse.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
post.releaseConnection();
}
I have generated following assertion
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="s2d3a451cf30560ca819118cf5785e722ea6da7b64" IssueInstant="2012-03-06T12:34:13Z"
Version="2.0">
<saml:Issuer>http://localhost:8080/opensso
</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#s2d3a451cf30560ca819118cf5785e722ea6da7b64">
<ds:Transforms>
<ds:Transform
Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>seHyxsFzsHCs0GaY7usF0DfMV58=
</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue> signature.....</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate> certificate.....</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
NameQualifier="http://localhost:8080/opensso" SPNameQualifier="https://saml.salesforce.com">deepakmule</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
NotOnOrAfter="2012-03-06T12:44:13Z"
Recipient="https://login.salesforce.com/?saml=MgoTx78aEPRbRaz0CkRqjaqrhP3sCa7w7.Y5wbrpGMNT07zKRYwcNWf0zs" />
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2012-03-06T12:34:13Z"
NotOnOrAfter="2012-03-06T12:44:13Z">
<saml:AudienceRestriction>
<saml:Audience>https://saml.salesforce.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2012-03-06T12:34:13Z"
SessionIndex="s27fb03a2b73bd8dc6846851bed7885b85e1d9ed6f">
<saml:AuthnContext>
<saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="userid">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">deepakmule</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
Are you trying to use the same IDP as you have configured for SSO for your Org, or are you trying to use the certificate added to a Remote Access application?
If you're trying to use your SSO configuration, then this looks pretty good - I'd check the SAML assertion validator
If you're trying to use the Bearer flow with a Remote Access application, then I'd look at the following
1) The Issuer should be the your Consumer Key from the remote access app ( the oauth client_id )
2) Post to our regular token endpoint
3) Use the salesforce username as the subject
4) Shorten the lifetime of your assertion to a minute
I'm very much new to silverlight, so please assume I've done something very daft....
I am trying to make a call from a silverlight app to a WCF service and check a value in the session. The value will have been put there by an aspx page. It's a little convoluted, but that's where we are.
My service looks like this:
[ServiceContract]
public interface IExportStatus
{
[OperationContract]
ExportState RequestExportComplete();
}
public enum ExportState
{
Running,
Complete
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExportStatus : IExportStatus
{
ExportState IExportStatus.RequestExportComplete()
{
// check value of session variable here.
}
}
The site that hosts the silverlight app also hosts the wcf service. Its web config looks like this:
<configuration>
<system.serviceModel>
<services>
<service name="SUV_MVVM.Web.Services.ExportStatus" behaviorConfiguration="MyBehavior">
<endpoint binding="basicHttpBinding"
bindingConfiguration="MyHttpBinding"
contract="SUV_MVVM.Web.Services.IExportStatus"
address="" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MyHttpBinding" />
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I added the service reference to my silverlight app using the VS tooling acepting the defaults (apart for the namespace)
Initially I was just trying to call the service like this:
var proxy = new ExportStatusClient();
proxy.RequestExportCompleteCompleted += (s, e) =>
{
//Handle result
};
proxy.RequestExportCompleteAsync();
But the session in the service was always empty (not null, just empty), so I tried manually setting the session Id into the request like this:
var proxy = new ExportStatusClient();
using (new OperationContextScope(proxy.InnerChannel))
{
var request = new HttpRequestMessageProperty();
//this might chnage if we alter the cookie name in the web config.
request.Headers["ASP.NET_SessionId"] = GetCookie("ASP.NET_SessionId");
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = request;
proxy.RequestExportCompleteCompleted += (s, e) =>
{
//Handle result
};
proxy.RequestExportCompleteAsync();
}
private string GetCookie(string key)
{
var cookies = HtmlPage.Document.Cookies.Split(';');
return (from cookie in cookies
select cookie.Split('=')
into keyValue
where keyValue.Length == 2 && keyValue[0] == key
select keyValue[1]).FirstOrDefault();
}
But what I'm finding is that the HtmlPage.Document.Cookies property is always empty.
So Am I just missing something really basic, or are there any other things that I need to change or test?
I just did a test from a Silverlight 4 application.
System.Windows.Browser.HtmlPage.Document.Cookies = "KeyName1=KeyValue1;expires=" + DateTime.UtcNow.AddSeconds(10).ToString("R");
System.Windows.Browser.HtmlPage.Document.Cookies = "KeyName2=KeyValue2;expires=" + DateTime.UtcNow.AddSeconds(60).ToString("R");
Each cookie expired as expected.
The value of System.Windows.Browser.HtmlPage.Document.Cookies...
Immediately after setting the cookies: "KeyName1=KeyValue1; KeyName2=KeyValue2"
30 seconds later: "KeyName2=KeyValue2"
60+ seconds later: ""