I currently have an API setup in Azure APIM with multiple operations.
I have implemented a JWT Bearer authentication policy on the All Operations section.
What I need to do now is implement the authorization part per operation based on the scopes returned in my token. I've looked at this example and understand what to do API Authorization Restriction
However, is it good/bad practice to try implement the policy on the root All operations and then in that policy check the operation being requested and write the code to match the correct scopes to operation.
Or should the JWT policy be copy/pasted for each operation and only that operations authorization logic then lives in there.
Thanks in advance.
So you're able to apply policies at the Global, Product , API and granular operation levels.
These policies are then evaluated together to form an Effective Policy for your request.
What I ended up doing was the applying the validate-jwt policy at the All Operations
level. This means that for any operation in my API, my token would be authenticated.
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Not authenticated, token invalid." output-token-variable-name="jwt">
<openid-config url="redacted" />
<audiences>
<audience>redacted</audience>
</audiences>
<issuers>
<issuer>redacted</issuer>
</issuers>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
I then added policies to the operations to perform the authorization by checking the scopes parameter in my JWT token, using the choose when policy. You need to make sure that you add this after the <base/> policy element.
<policies>
<inbound>
<base />
<choose>
<when condition="#(!((Jwt)context.Variables["jwt"]).Claims.GetValueOrDefault("scope").Contains("read:user"))">
<return-response>
<set-status code="403" reason="Forbidden" />
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Related
How do I pass a token to a backend service from API management with this policy? I have a C# azure function (http-trigger) that acts like an api, to access it users need to have a valid jwt token, I have that working fine. but I cannot seem to send the jwt token to the backend service.
<policies>
<inbound>
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config *******************************/>
<audiences>
<audience>***********************</audience>
</audiences>
<issuers>
<issuer>******************</issuer>
</issuers>
</validate-jwt>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Have you considered forward-request to send your HTTP request to your backend service?
<backend>
<forward-request />
</backend>
What worked was this
<value>#(context.Request.Headers.GetValueOrDefault("Authorization"))</value>
I am calling a REST API with a bearer token from my self-asserted-login technical profile. I have placed the call in the validation profiles as below -
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SignUpTarget">SignUpWithLogonUsernameExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="setting.showSignupLink">False</Item>
<Item Key="setting.forgotPasswordLinkLocation">none</Item>
<Item Key="ContentDefinitionReferenceId">api.signuporsignin</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
**<ValidationTechnicalProfile ReferenceId="SecureREST-AccessToken" ContinueOnError="false"/>
<ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignIn" ContinueOnError="true" />
<ValidationTechnicalProfile ReferenceId="login-NonInteractive"/>**
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
I can trace that the REST call is being made successfully with the bearer token in the header. However, the "login-NonInteractive" is not working. It is giving error "invalid username or password". However, if I remove below two steps the "login-NonInteractive" works fine.
It seems like there is a side effect from OAuth2 enabled REST call and "login-NonInteractive". They should be completely unrelated but the strange behavior halting my production.
**<ValidationTechnicalProfile ReferenceId="SecureREST-AccessToken" ContinueOnError="false"/>
<ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignIn" ContinueOnError="true" />**
Any help would be very much appreciated.
I wrote a simple application to test a RESTful API (provided by an accounting application). I have installed "Poster" in Firefox to test "GET and POST" XML and the API is behaving as it should. I wrote a simple "GET" test page to call the API from within the test CF8 application and the API returned the results I expected. I cannot POST from within the test CF8 application.
I have inserted the following into my application.cfm:
<!--- fix for HTTPS connection failures --->
<cfif NOT isDefined("Application.sslfix")>
<cfset objSecurity = createObject("java", "java.security.Security") />
<cfset objSecurity.removeProvider("JsafeJCE") />
<cfset Application.sslfix = true />
</cfif>
This is the code that is failing:
<cfprocessingdirective suppressWhiteSpace = "Yes">
<cfxml variable="customerxml">
<?xml version="1.0" encoding="UTFÂ8" standalone="yes"?>
<dataentry>
<interface name="Customer Edit"></interface>
<entity>
<attribute name="Customer Code">REP003</attribute>
<attribute name="Customer Name">Repsol3</attribute>
<attribute name="Address Line 1">El House</attribute>
<attribute name="Address Line 2">El Street</attribute>
<attribute name="Address Line 3">El Town</attribute>
</entity>
</dataentry>
</cfxml>
</cfprocessingdirective>
<cfhttp
method="post"
url="https://***/wsapi/1.1/dataentry/"
username="***"
password="***"
charset="utf-8">
<cfhttpparam type="header" name="Accept-Encoding" value="*" />
<cfhttpparam type="header" name="TE" value="deflate;q=0" />
<cfhttpparam type="header" name="Content-Type" value="application/xml" />
<cfhttpparam name="XML_Test" type="xml" value="#customerxml#">
</cfhttp>
There's a lot published on this topic and I have tried most things but some of the posts are about even older CF versions than mine! Any up-to-date help appreciated.
From the comments
The first thing that I try when receiving a connection failure using <cfhttp> is to verify that you can navigate to the URL using a browser from your ColdFusion server. If that request does not work then it will not work from the ColdFusion call either. Get that issue resolved first before proceeding.
Another common issue when connecting to secure sites using SSL (HTTPS) is that the certificate is not trusted or not known to ColdFusion (Java). In these cases you need to import their certificate into the Java keystore that is in use for ColdFusion.
Here is a great step by step instructions on how to install self-signed certs or other ssl certs that the Java library does not have installed.
http://www.coldfusioncookbook.com/entries/How-Do-I-Consume-SSL-Encrypted-Content-with-CFHTTP.html
Has helped me out a 1000 times.
Matt
I have a j2ee web application using spring web flow ang spring security. I want to redirect the user to page(maybe an error page) if the user's role has no access on the page being accessed because currently I get the error
Error 404--Not Found
From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.
If the server does not wish to make this information available to the client, the status code 403 (Forbidden) can be used instead. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address.
How do I do this redirection.I tried the access-denied-page attribute of security:http but I still get the error. Here's my configuration for security-http.
By the way.I am using Spring Faces and Facelets. Could this have been the cause of the problem?
<!-- Configure Spring Security -->
<security:http auto-config="true" access-denied-page="/deniedpage.xhtml"
session-fixation-protection="newSession">
<security:intercept-url pattern="/main.do"
access="ROLE_SUPERVISOR, ROLE_USER" />
<security:intercept-url pattern="/logoutSuccess.do"
access="ROLE_SUPERVISOR, ROLE_USER" />
<security:intercept-url pattern="/edit.do"
access="ROLE_SUPERVISOR" />
<security:intercept-url pattern="/register.do"
access="ROLE_SUPERVISOR" />
<security:intercept-url pattern="/admin_main.do"
access="ROLE_SUPERVISOR" />
<security:intercept-url pattern="/*"
access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:form-login login-page="/loginForm.do"
default-target-url="/main.do" authentication-failure-url="/loginForm.do?login_error=1" />
<security:logout logout-url="/logout.do"
invalidate-session="true" logout-success-url="/logoutSuccess.do" />
<security:concurrent-session-control
max-sessions="-1" exception-if-maximum-exceeded="true" expired-url="/loginform.do" />
</security:http>
The access-denied-page attribute of security:http should be enough, show us the Spring configuration you are using.
In the meantime try adding this to web.xml:
<error-page>
<error-code>404</error-code>
<location>notfound.jsp</location>
</error-page>
How can I set the Secure flag on an ASP.NET Session Cookie, so that it will only be transmitted over HTTPS and never over plain HTTP?
In the <system.web> element, add the following element:
<httpCookies requireSSL="true" />
However, if you have a <forms> element in your system.web\authentication block, then this will override the setting in httpCookies, setting it back to the default false.
In that case, you need to add the requireSSL="true" attribute to the forms element as well.
So you will end up with:
<system.web>
<authentication mode="Forms">
<forms requireSSL="true">
<!-- forms content -->
</forms>
</authentication>
</system.web>
See here and here for MSDN documentation of these elements.
There are two ways, one httpCookies element in web.config allows you to turn on requireSSL which only transmit all cookies including session in SSL only and also inside forms authentication, but if you turn on SSL on httpcookies you must also turn it on inside forms configuration too.
Edit for clarity:
Put this in <system.web>
<httpCookies requireSSL="true" />
Things get messy quickly if you are talking about checked-in code in an enterprise environment. We've found that the best approach is to have the web.Release.config contain the following:
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<authentication>
<forms xdt:Transform="Replace" timeout="20" requireSSL="true" />
</authentication>
</system.web>
That way, developers are not affected (running in Debug), and only servers that get Release builds are requiring cookies to be SSL.
Building upon #Mark D's answer I would use web.config transforms to set all the various cookies to Secure. This includes setting anonymousIdentification cookieRequireSSL and httpCookies requireSSL.
To that end you'd setup your web.Release.config as:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<httpCookies xdt:Transform="SetAttributes(httpOnlyCookies)" httpOnlyCookies="true" />
<httpCookies xdt:Transform="SetAttributes(requireSSL)" requireSSL="true" />
<anonymousIdentification xdt:Transform="SetAttributes(cookieRequireSSL)" cookieRequireSSL="true" />
</system.web>
</configuration>
If you're using Roles and Forms Authentication with the ASP.NET Membership Provider (I know, it's ancient) you'll also want to set the roleManager cookieRequireSSL and the forms requireSSL attributes as secure too. If so, your web.release.config might look like this (included above plus new tags for membership API):
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<httpCookies xdt:Transform="SetAttributes(httpOnlyCookies)" httpOnlyCookies="true" />
<httpCookies xdt:Transform="SetAttributes(requireSSL)" requireSSL="true" />
<anonymousIdentification xdt:Transform="SetAttributes(cookieRequireSSL)" cookieRequireSSL="true" />
<roleManager xdt:Transform="SetAttributes(cookieRequireSSL)" cookieRequireSSL="true" />
<authentication>
<forms xdt:Transform="SetAttributes(requireSSL)" requireSSL="true" />
</authentication>
</system.web>
</configuration>
Background on web.config transforms here: http://go.microsoft.com/fwlink/?LinkId=125889
Obviously this goes beyond the original question of the OP but if you don't set them all to secure you can expect that a security scanning tool will notice and you'll see red flags appear on the report. Ask me how I know. :)
secure - This attribute tells the browser to only send the cookie if the request is being sent over a secure channel such as HTTPS. This will help protect the cookie from being passed over unencrypted requests. If the application can be accessed over both HTTP and HTTPS, then there is the potential that the cookie can be sent in clear text.