When receiving values in a url with a period ".", somehow Taffy doesn't like it and doesn't show results. For example:
Endpoint URL:
mydomain.com/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pa.com.cnn.com
CFComponent:
<cfcomponent extends="taffy.core.resource"
taffy:uri="/v1/devices/{deviceid}/registrations/{registrationid}" >
<cffunction name="get" access="public" output="false" >
<cfset var retCode = 200>
<cfreturn representationOf("/v1/devices/#arguments.deviceid#/registrations/#arguments.registrationid#").withStatus(retCode) />
</cffunction>
</cfcomponent>
When I remove the periods, for example:
Endpoint URL:
mydomain.com/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pacomcnncom
Results:
"/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pacomcnncom"
A bit late but I assume you're using Taffy.
Taffy, because it parses for file extensions to set mime-types of its responses, cannot have extraneous 'dots' in the URI. There are workarounds apparently . . .
You can use regex to refine the taffy_uri.
https://github.com/atuttle/Taffy/wiki/Custom-token-regular-expressions
I've tried this but not had success, opting to not have an end point requiring valid email address on the URI. Instead, posting the email address in the POST body.
More info here
https://groups.google.com/forum/#!msg/taffy-users/HbYCeCvuTLA/1-eco35pAwAJ;context-place=forum/taffy-users
B.
Related
I need to post from a non-secure CF page to a secure CF page. I don't want to have to go through and implement the user authentication on the page sending the values because its a rather cumbersome process due to the way this legacy site was setup and secondly because the page sending the values is acting as a service between two unrelated order management systems as opposed to a user.
Right now, when I try to post to, the response result is a redirect to the login of the homepage. Is there a way to make an exception for a posting or receiving page from forcing user authentication?
I'm using <cfhttp> to post the values to post page which has a series of <cfparam>'s that I'm passing the values to. Once I pass those values into the post page is when the post page triggers a redirect to the home page because the post page is an internal page in the order management system and is displayed as a client logs in and a session is created for them.
Since you did not provide any code, here is a guess what it might look like and how you could add an exception for specific requests:
<cffunction name="onRequestStart" access="public" output="false" returnType="boolean">
<cfargument name="targetPage" type="string" required="true">
<!--- treat initialized SESSION or matching request token (rtoken) as successful authentication --->
<cfset LOCAL.isAuthenticated = (
isDefined("SESSION.userID")
or
( structKeyExists(FORM, "rtoken") and (FORM["rtoken"] eq "some-secret-only-you-know") )
)>
<cfif LOCAL.isAuthenticated>
<!--- do something... --->
<!--- not authenticated --->
<cfelse>
<!--- redirect to login --->
<cflocation url="login.cfm" statusCode="303" addToken="false">
</cfif>
</cffunction>
Now you could simple add the key-value-pair rtoken=some-secret-only-you-know (i.e. <input type="hidden" name="rtoken" value="some-secret-only-you-know" />) to your POST to bypass the session based authentification.
Disclaimer: Only use this method if the POST parameters (form fields) are not public/editable by the user.
Feel free to provide actual context so I can assist in a more concrete way.
I have written a couple of apps with similar, but not identical requirements. Here is how I handled those requirements in the last one I wrote. All this code is the Application.cfc file in the methods specified.
In onApplicationStart:
application.securityNotNeededPages =
"somePage.cfm,someOtherPage.cfm,someMorePages.cfm";
In onRequestStart
var ThisPage = listlast(cgi.PATH_INFO, "/");
...
if (ListFindNoCase(application.securityNotNeededPages, ThisPage) is false) {
security related code
}
else {
code for when the page does not to be secured
}
I created a new function in an existing REST cfc but when I am trying to call it I receive a 404 Error where the rest of the functions are working. All of the functions are following the same structure as the one I am about to link further down without any issues.
I saw another post like mine but I didn't find any answers in it. This is the link for the other post here
<cfcomponent restpath="student" rest="true">
<cffunction name="npssummary" access="remote" output="false" returntype="any" httpmethod="get" restpath="npssummary" produces="application/json">
<cfquery name="nps_summary" datasource="dpsigweb2">
select top 10 * from contact
</cfquery>
<cfreturn serializeJSON(nps_summary,"struct")>
</cffunction>
</cfcomponent>
And this is how I am calling it
<cfhttp url="http://dev.example.com/rest/IIT/student/npssummary" method="get">
<cfset results = "#cfhttp#">
<cfdump var="#results#">
When I am trying to call the function directly in the browser I receive the expected result.
Also, I am using this function to reset the REST services each time I make a change to my component it seems to be working as expected so far.
<cftry>
<cfset restInitApplication("Z:\Sites\testSites\API\","IIT")>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
This is a browser limitation:
Microsoft Internet Explorer has a maximum uniform resource locator (URL) length of 2,083 characters. Internet Explorer also has a maximum path length of 2,048 characters. This limit applies to both POST request and GET request URLs.
If you are using the GET method, you are limited to a maximum of 2,048 characters, minus the number of characters in the actual path.
However, the POST method is not limited by the size of the URL for submitting name/value pairs. These pairs are transferred in the header and not in the URL.
RFC 2616, "Hypertext Transfer Protocol -- HTTP/1.1," does not specify any requirement for URL length.
Im my Application.cfc I am trying to use the onRequestStart() function to protect my pages as such:
<cffunction name="onRequestStart" access="public" returntype="boolean">
<cfargument type="String" name="TargetPage" required="true"/>
<!--- Define which pages don't need protection --->
<cfset APPLICATION.AllowedPages = "/index.cfm, /register.cfm">
<!--- Create an instance of the page-protect.cfc --->
<cfset APPLICATION.PageProtect = CreateObject("component", "page-protect")>
<!--- check if the current page is an allowed page --->
<cfif #ListFindNoCase(APPLICATION.AllowedPages, ARGUMENTS.TargetPage)# EQ 0>
<!--- if its not an allowed page, then protect it --->
<cfscript>
APPLICATION.PageProtect.PageProtectBasic(argumentcollection = session);
</cfscript>
</cfif>
<cfreturn true>
</cffunction>
This code works (kind of as you will see later). Page-protect.cfc is very simple and does this:
<cfcomponent displayname="page-protect" output="false">
<cffunction name="PageProtectBasic" output="no">
<cfif NOT structKeyExists (SESSION, 'Auth')>
<cflocation url="/index.cfm" addtoken="no">
</cfif>
</cffunction>
</cfcomponent>
So if the Auth structure within the SESSION scope does not exist, then this user is not logged in and should be taken back the homepage. A logout method in a different file deletes the Auth structure from SESSION and also clears the SESSION scope (if definitely does this I have tested it).
The onRequestStart() page protection works initially but I have noticed that when I press the back button on my browser it will show the previous page that I just logged out of. This should be a protected page and not display but I guess its a browser cache so not a problem. However the problem is that if I click on a link in this page it SHOULD not allow it and send the user back to home page (because the SESSION.Auth structure does not exist and SESSION has been cleared). But it does not send the user back to the homepage anymore, it just shows a ColdFusion error page stating that "Element AUTH.{element_name} is undefined in SESSION".
So for some reason its not going back to the homepage despite the user not being logged in, and instead is trying to load the protected page and then falling over because a variable within the SESSION.AUTH structure does not exist. I simply don't understand what I'm doing wrong. Please help!
While James Mohler provides some very helpful pointers on how to improve your code in general the issue you are having is not related to that.
The reason that users can see these pages on hitting back is because they are cached in the browser. This is the browser trying to be helpful and not requesting data from the server that it has already seen. The browser being a good internet citizen will do what it is told though. So you need to return the correct HTTP headers to tell it that you don't want it to cache them. E.g.
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
So to do this in CF
<cfheader name="Cache-Control" value="no-cache, no-store, max-age=0, must-revalidate">
<cfheader name="Pragma" value="no-cache">
If you add the above to the pages that are concerning you, the problem will go away.
Simon
Sorry, this won't fit into a comment box
I think what you are trying to do is something like this:
onApplicationStart() {
APPLICATION.PageProtect = CreateObject("component", "page-protect")>
}
onSessionStart() {
session.auth = false; // it is easier to work with if it always exists
}
onRequestStart() {
if (ListFindNoCase(APPLICATION.AllowedPages, ARGUMENTS.TargetPage) EQ 0)
// if its not an allowed page, then protect it
APPLICATION.PageProtect.PageProtectBasic(argumentcollection = session);
}
}
Possibly not related to your problem but this line might have a couple of issues.
<cfset APPLICATION.AllowedPages = "/index.cfm, /register.cfm">
Issue number 1 is the leading slashes. Unless arguments.TargetPage has those slashes, and they might, you are not going to get the expected behaviour.
Issue number 2 is the space between your two list items. Leading spaces are part of the list item which could lead to unexpected behaviour on register.cfm.
We use GA for tracking and part of the tracking involves storing the __utmz cookie value in our DB. I have a problem in understanding why is CF 10 not able to parse the __utmz cookie.
CF10 is not parsing or properly retrieving the value of __utmz cookie Or just about any cookie value that has an 'equal (=)' sign in it other than the CFGLOBALS.
Here is the screen shot of the issue (using CFDUMP of COOKIE scope) -
What it should look like -
What it is looking like -
Server Config: CF10, IIS 7.5, Win 2k8
Ok! I found the way to mitigate this problem. By using the GetHttpRequestData() method.
<cfscript>
_cookie = GetHttpRequestData().headers.cookie;
</cfscript>
This will return an ; delimited list of cookie values. I used regEx to pick the __utmz value I needed.
I just ran into this problem. Some code that was working in CF8 stopped working in CF10. I created this function to get the raw cookie value:
<cffunction name="GetRawCookie" output="false" returntype="string">
<cfargument name="cookieName" type="string" required="true">
<cfset local.cookies = GetHttpRequestData().headers.cookie>
<cfset local.cookieValue = "">
<cfset local.match = reFindNoCase("(?:^|;)\s*" & arguments.cookieName & "=([^;]+)", local.cookies, 1, true)>
<cfif local.match.pos[1] gt 0>
<cfset local.cookieValue = mid(local.cookies, local.match.pos[2], local.match.len[2])>
</cfif>
<cfreturn local.cookieValue>
</cffunction>
I'm working with ColdFusion 9.0.1 and latest (for current date) stable build of twitter4j library - twitter4j-core-2.2.4. I'm trying to create functionality which allows users to login or register at our site using their twitter accounts.
I was able to create authorization part: user click on the link on our site and system redirects him to twitter page. On this page he able to "Authorise" our application. After that system redirecting him back using callBackURL.
But I have a problem with next step. When I'm trying to setOAuthAccessToken and for that trying to instantiate AccessToken object with follow part of code:
accessToken = createObject( 'java', 'twitter4j.auth.AccessToken' ).init( 'myStoredRequestToken', 'myStoredRequestTokenSecret' );
But I have follow error:
An exception occurred while instantiating a Java object. The class
must not be an interface or an abstract class. Error: ''.
Any ideas?
Update:
The start part of stacktrace:
'coldfusion.runtime.java.JavaObjectInstantiationException: Object instantiation exception. at coldfusion.runtime.java.JavaProxy.CreateObject(JavaProxy.java:171) at coldfusion.runtime.java.JavaProxy.invoke(JavaProxy.java:80) at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2360) at cftwitter2ecfc2084917956$funcGETUSERCREDENTIALS.runFunction(C:\inetpub\wwwroot_test\twPlayGrnd_com\twitter.cfc:36) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:472) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:368) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:55) at ...
...cut here, not sure this is important...
the last part is
cfapplication2ecfc665259542$funcONREQUEST.runFunction(C:\inetpub\wwwroot_test\twPlayGrnd\application.cfc:55) ... 55 more Caused by: java.lang.IllegalArgumentException: Invalid access token format. at twitter4j.auth.AccessToken.(AccessToken.java:50) ... 60 more'
I saw the message about wrong format, but based on documentation at http://twitter4j.org it should accept two agruments (strings with keys). Am I wrong?
Update 2
*just find that out - I am sorry that I brought you into confusion with my first post and example... of course I used myStoredRequestToken, myStoredRequestTokenSecret, not a consumer key/secret *
*there are relevant parts of code I'm using for this functionality*
application.cfc ("onApplicationStart" function, instantiating components on start of application)
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false">
...
<cfset application.com.twitterInstance = server.javaloader.create("twitter4j.TwitterFactory").getInstance() />
<cfset application.com.twitter = createObject("component","_com.twitter").init() /> *<!--- cfc component which will be listed below --->*
...
</cffunction>
twitter.cfc (corresponding coldfusion component)
<cfcomponent displayname="twitter" output="false">
<cffunction name="init" access="public" output="false">
<cfreturn this>
</cffunction>
<cffunction name="authorizeTwitter" access="public" output="false">
<cfargument name="callBackURL" type="string" required="false" default="#request.twtCallBackURL#" />
<cfset var requestToken = "" />
<cfset application.com.twitterInstance.setOAuthConsumer(request.twtConsumerKey,request.twtConsumerSecret) />
<cfset requestToken = application.com.twitterInstance.getOAuthRequestToken(arguments.callBackURL) />
<cflock scope="session" type="exclusive" timeout="10">
<cfset session.oAuthRequestToken = requestToken.getToken()>
<cfset session.oAuthRequestTokenSecret = requestToken.getTokenSecret()>
</cflock>
<cflocation url="#vLocal.requestToken.getAuthorizationURL()#" addtoken="No" />
</cffunction>
<cffunction name="getUserCredentials" access="public" output="true">
<cfset var vLocal = {} />
<cfset vLocal.accessToken = "" />
<cfset vLocal.userData = "" />
<cfset vLocal.requestToken = "" />
<cfset vLocal.accessToken = server.javaloader.create("twitter4j.auth.AccessToken").init(session.oAuthRequestToken,session.oAuthRequestTokenSecret)>
<cfset application.com.twitterInstance.setOAuthAccessToken(vLocal.accessToken) />
<cfset vLocal.userData = application.com.twitterInstance.verifyCredentials() />
<cfdump var="#vLocal.userData#" label="User Credentials">
</cffunction>
First function is for first step - requesting twitter for autorization page (where user can autorize or deny application). Call back URL runs the page what calls the second function and I have problem only at this step (line for generation accessToken).
I have the same result if Im using createObject function instead of javaloader.
*So, my main question is still the same - to obtain the users unique Access Token? Please point me, what I'm doing wrong? What is a correct format for unique user's accessToken generation? Should I place oauth_verifier parameter there? if so, how?*
You are passing consumer key/secret instead of access token/secret.
You can generate your access token/secret at dev.twitter.com.
https://dev.twitter.com/apps ยป create my access token
Best,
Yusuke
I think I figured out what is wrong with the help of the examples 8. Sign in with Twitter and
Adding support for automated tweets with OAuth. Only tested with my own account though ..
Before you redirect to the authorization page, save the whole RequestToken object in a session variable. You will need it to extract the AccessToken. Note: I am storing the TwitterFactory in the application scope - not the instance
<cfset Twitter = application.TwitterFactory.getInstance()>
<cfset Twitter.setOAuthConsumer(application.TwitterConsumerKey, application.TwitterConsumerSecret)>
<cfset Session.RequestToken = Twitter.getOAuthRequestToken( YourCallBackURL )>
On callback, twitter adds a parameter named oauth_verifier to the URL. Use that value and the saved RequestToken to extract the AccessToken.
<cfset AccessToken = Twitter.getOAuthAccessToken(Session.RequestToken, URL.oauth_verifier)>
<cfset session.StoredAccessToken = AccessToken.getToken()>
<cfset session.StoredAccessSecret = AccessToken.getTokenSecret()>
Once you have the AccessToken/Secret you can access user details (update status,...) anywhere.
<cfset Twitter = application.TwitterFactory.getInstance()>
<cfset Twitter.setOAuthConsumer(application.TwitterConsumerKey,application.TwitterConsumerSecret)>
<cfset AccessToken = createObject("java", "twitter4j.auth.AccessToken")>
<cfset OAuthToken = AccessToken.init(session.StoredAccessToken, session.StoredAccessSecret)>
<cfset Twitter.setOAuthAccessToken(OAuthToken)>
<cfset userData = Twitter.verifyCredentials()>
<cfoutput>
id = #userData.getId()#<br>
name = #userData.getName()#<br>
followers = #userData.getFollowersCount()#<br>
friends = #userData.getFriendsCount()#<br>
</cfoutput>