Showing posts with label authorization. Show all posts
Showing posts with label authorization. Show all posts

Saturday, September 15, 2018

GCP Authentication: RefreshError

Leave a Comment

In order to round-trip test mail sending code in our GCP backend I am sending an email to a GMail inbox and attempting to verify its arrival. The current mechanism for authentication to the GMail API is fairly standard, pasted from the GMail API documentation and embedded in a function:

def authenticate():     """Authenticates to the Gmail API using data in credentials.json,     returning the service instance for use in queries etc."""     store = file.Storage('token.json')     creds = store.get()     if not creds or creds.invalid:         flow = client.flow_from_clientsecrets(CRED_FILE_PATH, SCOPES)         creds = tools.run_flow(flow, store)     service = build('gmail', 'v1', http=creds.authorize(Http()))     return service 

CRED_FILE_PATH points to a downloaded credentials file for the service. The absence of the token.json file triggers its re-creation after an authentication interaction via a browser window, as does the token's expiry.

This is an integration test that must run headless (i.e. with no interaction whatsoever). When re-authentication is required the test currently raises an exception when the authentication flow starts to access sys.argv, which means it sees the arguments to pytest!

I've been trying to find out how to authenticate reliably using a mechanism that does not require user interaction (such as an API key). Nothing in the documentation or on Stackoverflow seems to answer this question.

A more recent effort uses the keyfile from a service account with GMail delegation to avoid the interactive Oauth2 flows.

def authenticate():     """Authenticates to the Gmail API using data in g_suite_access.json,     returning the service instance for use in queries etc."""     main_cred = service_account.Credentials.from_service_account_file(         CRED_FILE_PATH, scopes=SCOPES)     # Establish limited credential to minimise any damage.     credentials = main_cred.with_subject(GMAIL_USER)     service = build('gmail', 'v1', credentials=credentials)     return service 

On trying to use this service with

        response = service.users().messages().list(userId='me',                                     q=f'subject:{subject}').execute() 

I get:

google.auth.exceptions.RefreshError:   ('unauthorized_client: Client is unauthorized to retrieve access tokens using this method.',    '{\n "error": "unauthorized_client",\n "error_description": "Client is unauthorized to retrieve access tokens using this method."\n}') 

I get the feeling there's something fundamental I'm not understanding.

1 Answers

Answers 1

The service account needs to be authorized or it cant access the emails for the domain.

"Client is unauthorized to retrieve access tokens using this method"

Means that you have not authorized it properly; check Delegating domain-wide authority to the service account

Source: Client is unauthorized to retrieve access tokens using this method Gmail API C#

Read More

Saturday, April 14, 2018

How can I impersonate a user of AppEngine java application operating in G-Suite domain?

Leave a Comment

In my standard AppEngine application I want to perform changes in a Google Sheet documents (among others).

To achieve this, I need to obtain a credential for service account, and somehow configure that it should act in behalf of a user.

This method allows gives me default service account credentials:

private static GoogleCredential getDefaultServiceAccountCredential() throws IOException {     return GoogleCredential.getApplicationDefault()         .createScoped(MY_SCOPES); } 

but it does not work in behalf of a user.

Following code is similar, uses other (non-default) service account, but still no impersonation happens:

private static GoogleCredential getNonDefaultServiceAccountCredential() throws IOException {     return GoogleCredential.fromStream(IncomingMailHandlerServlet.class.getResourceAsStream("/tokens/anoher-e6351a8c5b91.json"))         .createScoped(MY_SCOPES); } 

For impersonation, Google Docs (and many SO advices) mentions how to do it with use of PKCS12 file; however, that file can only be read as PrivateKey on installed application and not on AppEngine.

Is there any way to obtain impersonated credential for java application running in AppEngine? Or, is there a trick to read from a File on AppEngine?

Note that, for all service accounts that I tried, I configured them with role Owner and with DwD (Domain-wide delegation). Is there anything else to configure?

1 Answers

Answers 1

The GoogleCredential reference offers a sample to

also use the service account flow to impersonate a user in a domain that you own. This is very similar to the service account flow above, but you additionally call GoogleCredential.Builder.setServiceAccountUser(String)

 public static GoogleCredential createCredentialForServiceAccountImpersonateUser(       HttpTransport transport,       JsonFactory jsonFactory,       String serviceAccountId,       Collection<String> serviceAccountScopes,       File p12File,       String serviceAccountUser) throws GeneralSecurityException, IOException {     return new GoogleCredential.Builder().setTransport(transport)         .setJsonFactory(jsonFactory)         .setServiceAccountId(serviceAccountId)         .setServiceAccountScopes(serviceAccountScopes)         .setServiceAccountPrivateKeyFromP12File(p12File)         .setServiceAccountUser(serviceAccountUser)         .build();   } 
Read More

Sunday, October 8, 2017

Connecting, authorizing and getting data for a web application using PHP

Leave a Comment

Any help/advice/direction would be greatly appreciated. Try bearing with me even if this question is not specific.

I am working on a web application which will connect to a pre-existing commercial cloud-based calendar which will have schedules for a certain event.

I will have a authorize button which will simply ask the users to enter their credentials for that cloud-based calendar. Once users enter their credentials successfully, I want my application to connect to the cloud-based application's database and fetch the necessary data.

The flow will be like

Users -> Click Authorize button -> Enter credentials -> Connect to the system -> Get the necessary data -> Update it in my web application.

I am on a point of drawing a blank because I don't find any useful resources on how to gain access to a separate application and fetching the data. I am aware I have to build an API of some sort to communicate with that system, but I don't know exactly HOW.

Sorry, if I am not making sense, but I really want some help here. Are there some libraries which provide a similar functionality? How should I even start? I am using PHP as a server-side language.

4 Answers

Answers 1

  1. Button On Click -> Redirect to Login Form

  2. Loging Form ->User Enters Credentials -> Submit Form

  3. In the respective action page ie. the page where you will post the data, you will have Username/Email and Password

  4. You have to authenticate. Now to authenticate you can't have the direct access to the other server database (cloud database directly) so you need to call the API of the respective cloud base database for which you want to authenticate. For this call, you can use CURL call with POST parameters or any necessary HTTP request like GET, POST, PUT, DELETE, PATCH. Make sure you use the TOKEN based API call. Even you can go for any respectively secured API calls as per the cloud database design for security.

BONUS: So what is token-based API call? Whenever you're requesting the API call to cross server ie. other servers make sure you can some random text sent along with the other parameters. The server on the other hand which received your request make sure to validate this token from its respective database table to make sure that you're the valid user and allows you to perform the necessary action like get customer details, get product details and so on.

  1. The authentication API returns the AUTHENTICATED data. Based on that you can continue to perform the actions.

  2. In case if the authentication fails, then you can flash the invalid credentials error message to the user.

  3. If its success then you will be granted the access and you can now perform an insertion data to your database.

  4. To read the data from the other database table, since you won't have the necessary permission you can't directly access it. Make the API call to the respective function to get all the necessary data, whether it may be GET, POST, PUT, DELETE, PATCH.

  5. As of now think that you want to get all the data of table CUSTOMER then you will have to make GET request to the API which returns the JSON data.

  6. Now its left to you what you want to do with this data. Whether you want to save this in your respective database table or play around with it on the fly.

To learn how to write the API's

Eg:

NOTE: I have not added any security check make sure you work out on the same

Think that your doing GET request to get the details of the customers then you can do like the following

API URL: http://127.0.0.1/project/getCustomers.php?token=2fdsd5f42314sfd85sds REQUEST METHOD: GET

getCustomers.php

<?php include_once 'dbConnect.php'; //I am having $link as database link //Only !isset will also work $errors = []; if(empty($_GET['token']) || !isset($_GET['token'])){     $errors[] = 'Token not found!'; }else{     $token = $_GET['token']; } //tokens table will have (id, user_id, token) coloumns $tokenQuery = mysqli_connect($link, "SELECT * FROM tokens WHERE token = '$token' LIMIT 1"); //If I get any result with the respective token if(mysqli_num_rows($tokenQuery) > 0){     $tokenDetails = mysqli_fetch_assoc($tokenQuery);     $userId = $tokenDetails['user_id'];     /* Now you can check whether the user has Authorization to access the particular module */     $isUserAuthorized = checkUserAuthorizationModule($userId); //Please help your self to do this all checks      if($isUserAuthorized === TRUE){         $customersQuery = mysqli_query($link, "SELECT * FROM customers");         $customersDetails = [];         if(mysqli_num_rows($customersQuery) > 0){             while($row = mysqli_fetch_assoc($customersQuery)){                 $customersDetails[] = $row;             }         }          return json_encode([             'customerDetails' => $customersDetails         ]);     } }else{     $errors[] = 'Token is not valid'; }  return json_encode([     'errors' => $errors ]); 

Answers 2

There's one way you could do it...

I'm gona get creative here:

  1. Hit an API endpoint on your server, deliver 'username' and 'password'.

  2. Store username and password to a .txt file on this server. The name of the txt file is the timestamp 'now'

  3. On this same server, launch a chain of USER INTERFACE commands, something like this (using a library like xdotool):

    • move the mouse to mozilla icon on the desktop,
    • double-click on mozilla,
    • move the mouse to the address bar,
    • go to the calendar website,
    • move mouse,
    • write username you got from user,
    • tab,
    • write password you got from user,
    • hit enter,
    • move mouse to place where you download calendar to csv (or you can select, and ctrl-c copy),
    • using mouse, save the file to a public html directory of server (name it the same you named the txt file up there).
  4. have the client webapp check constantly for that .txt file with the calendar info. Once the info is fetched, display it on your screen.

Voila.

Answers 3

Depends much on the resources available ate the platform. But if it has PHP, you can implement RESTFUL services that exchange data using JSON as Channaveer Hakari response, except that maybe you wouldn't take data from mySQL, but the flow and technologies and protocol are that (RESTFULL services, data delivered JSON type, because it can be consumed on a great variety of programming languages).

Answers 4

It really depends on how the cloud calendar likes to be interacted with.

Are you able to tell us what service it is?

For example, if it supports OAuth that may be a way to register your app with the service for that user, and then allow your app to update data to their account. This is how for example Facebook works when it asks your for a third party website to have permission to look at your contacts and make posts to your wall etc. This is almost the defacto standard of the Internet these days for your use case.

Alternatively it could be a case of like you said, grabbing their credentials and storing them, then connecting to the calendars REST API with those credentials and making updates. I would say this is a bad approach from a security point of view. No user should give their credentials to a third party and trust them. That is a bad idea. It's one of the reasons OAuth exists.

If you're building a small app for a small company for internal use only the second approach may be fine. I'll leave it up to you to decide.

Read More

Saturday, September 9, 2017

Lists and pagination authorization in GraphQL business layer

Leave a Comment

In Dan Schafer's excellent "GraphQL at Facebook" talk from React Europe he goes over how centralizing authorization in business layer models avoids the problem of having to duplicate authorization logic for every edge that leads to an authorized node.

Three layer

This works fine for something like Todo.getById(1) which in my case eventually ends up querying a database for SELECT * from todos WHERE id=1 and then verifying authorization with checkCanSee(resultFromDatabase).

However, let's say my todos table now contains 100,000 todos from multiple users, performing authorization purely in the business layer becomes impractical as I'd need to fetch every todo, filter the result using the shared authorization logic and then slicing that to perform pagination.

Am I wrong thinking that the only way to solve this is by letting authorization logic reside in the persistence layer itself?

2 Answers

Answers 1

I think one of the takeaways from Dan’s talk is the difference in how authorization is handled with GraphQL, as opposed to a typical REST endpoint.

In REST, each resource is typically associated with a single endpoint. When a request is made to that endpoint, it makes sense to check whether the requestor is authorized before processing the request. With GraphQL we may be fetching multiple resources within the same request, so this behavior is no longer desirable. As Dan puts it:

We don’t want to completely blow up the request if you can’t see one of [the requested resources].

So the preferred approach with GraphQL is to implement some kind of per-node mechanism for authorization, and to only return the resources the requester is authorized to see. And that is exactly what the example in the talk shows – one way of doing that.

If you store your to-dos in a SQL database table, it would make perfect sense for your code to just make a query like SELECT * from todos WHERE creator_id=${viewer.id} and omit using a function like checkCanSee altogether.

Similarly, you can bake pagination right into your query with limit-offset, cursors, etc. And yes, since you’re now letting your DB do the heavy lifting, you could say that we’ve moved into the persistence layer. However, it’s still up to your business logic to take the request, sanitize the inputs, construct an appropriate query and return the results in a form GraphQL can use.

I can’t speak for Dan, but I imagine his intent was not to suggest this was the only (or even optimal) way to implement authorization for a node. I think the bigger point is that if you are, for example, fetching:

{   header   todos  {     description   }   quoteOfTheDay } 

even an unauthorized client should still get a response back from the server that it can then use to render a page for the end-user (even if that response includes an empty array of to-dos).

Answers 2

You can query based on authorization results. In your Todo example:

  1. Ask the authorization server whose todos you're allowed to see,
  2. SELECT * FROM todos WHERE owner IN [<permitted owners]]
Read More

Saturday, March 18, 2017

JWT authentication in SignalR (.NET Core) without passing token in Query String

Leave a Comment

I am using JWT authentication tokens in an ASP .NET Core Web API application. The tokens are generated by the API itself, not by a third party. I added SignalR sucessfully to the stack, but now I need to authenticate the users that are trying to execute server (Hub) methods. Someone suggested to pass the token in the "qs" property in JavaScript. This will not work for me as our tokens are really large (they contain lots of claims). I tried writing a custom middleware for reading the token from the payload and auto-authenticating the user. The problem is that, when using WebSockets, the middleware is not executed. Any ideas will help.

1 Answers

Answers 1

Have a look at article that suggests to use query string Authenticate against a ASP.NET Core 1.0 (vNext) SignalR application using JWT. I know that you token is too long, but author explains how to use middleware to authenticate the request.

Here is the summary from the article:

  • SignalR does not have any special authentication mechanism built in, it is using the standard ASP.NET authentication.
  • JWT is typically sent in the Authorization header of a request
  • The SignalR JavaScript client library does not include the means to send headers in the requests, it does however allow you to pass a query string
  • If we pass the token in the query string we can write a middleware that adds a authorization header with the token as its value. This must be done before the Jwt middleware in the pipeline
  • Be aware of the “Bearer ” format

I have highlighted the key point that your custom middleware should be registered before Jwt middleware.

Read More

Tuesday, February 28, 2017

Jwt tokens authorization is not working

Leave a Comment

I'm trying to create Jwt token authorization. For this purpose I have issuer part with the code like that:

public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) {     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});     Users user;     using (var db = new UserStore())     {         user = Task.Run(()=> db.FindUser(context.UserName, context.Password, context.ClientId)).Result;     }     if (user == null)     {         context.SetError("invalid_grant", "The user name or password is incorrect");         return Task.FromResult<object>(null);     }     var identity = new ClaimsIdentity("JWT");     identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));     identity.AddClaim(new Claim("sub", context.UserName));     identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Name));      var props = new AuthenticationProperties(new Dictionary<string, string>     {         {             "audience", context.ClientId ?? string.Empty         }     });     var ticket = new AuthenticationTicket(identity, props);     context.Validated(ticket);     return Task.FromResult<object>(null); } 

And "resource" part that should accept bearer token:

public void ConfigureOAuth(IAppBuilder app) {     var issuer = SiteGlobal.Issuer;     var audience = SiteGlobal.Audience;     var secret = TextEncodings.Base64Url.Decode(SiteGlobal.Secret);     app.UseJwtBearerAuthentication(     new JwtBearerAuthenticationOptions     {         AuthenticationMode = AuthenticationMode.Active,         AllowedAudiences = new[] { audience },         IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]         {             new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)         }     }); } 

As far as I can see issued token are valid (I did validation on jwt.io), so the problem is somehwere else. When I'm sending token in Postman with the call to controller protected by [Authorize] attribute it always return 401 code. Could you please advise how to fix this?

P.S. This is how I implement custom Jwt fortmat:

public string Protect(AuthenticationTicket data) {     if (data == null)     {         throw new ArgumentNullException("data");     }     string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;     if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");     Audience audience;     using (var store = new AudienceStore())     {         audience = Task.Run(()=> store.FindAudience(audienceId)).Result;     }     var symmetricKeyAsBase64 = audience.Base64Secret;     var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64));     var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);     var issued = data.Properties.IssuedUtc;     var expires = data.Properties.ExpiresUtc;     var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials);     var handler = new JwtSecurityTokenHandler();     var jwt = handler.WriteToken(token);     return jwt; } 

P.S. Guys, I'm so sorry, but I forgot to explain that "issuer" part of code that's standalone application, meanwhile "audience" is protected web api. That's two different appliactions running independently.

2 Answers

Answers 1

In Postman ensure you are sending the authorization header using the following format:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

Postman Authorization Header

Ensure that you leave the Authorization tab set to Type: No Auth.

If you continue to have issues, set a breakpoint in your GrantResourceOwnerCredentials and see if it gets to that point. Also consider overriding the ValidateClientAuthentication method of OAuthAuthorizationServerProvider which should get called prior to GrantResourceOwnerCredentials if you want to debug earlier in the chain of events.

Answers 2

I have just tried to run demo project mentioned in SON Web Token in ASP.NET Web API 2 using Owin and all worked as expected.

I noticed that your implementation of Protect method differs quite a bit. I would suggest you to compare your implementation to an example given in the article. Try make that work first.

Also please make sure that issuer, audience and secret are same on both servers.

If you provide complete source code I can try to investigate more.

Read More

Sunday, October 9, 2016

Authorization method for REST API utilising Active Directory

Leave a Comment

What is the best method of securing a REST Web API with the following requirements. The system has an Angular JS frontend with the REST APIs implemented in ASP.net.

  • There are two "roles" in the system, users will have one of the roles. One role should allows access to some APIs (call it "VIEW"), the other role allows access to other APIs
  • All users are in Active Directory, so if I have a username, I can check what role they are in- Some clients are on Windows boxes, the others are on Linux
  • I would like to persist the session so I don't have to look up AD for every API call
  • I would like single sign on. On the Windows machines, I don't require them to enter user and pass as I already can retrieve their username using Windows Authentication.

I believe that Oauth would be my best option.

2 Answers

Answers 1

There are two "roles" in the system, users will have one of the roles. One role should allows access to some APIs (call it "VIEW"), the other role allows access to other APIs

  • For role based authentication, you can use [Authorize("Role" = "Manager")]. The token will be provided by the identity server and will contain the claim as Role.

All users are in Active Directory, so if I have a username, I can check what role they are in- Some clients are on Windows boxes, the others are on Linux

  • If you have ADFS then you can have an Identity server that trusts the ADFS. The ADFS will provide a token which will have the claim for role and your Identity Server will do the claims transformation and will return the same Role claim back to angular app.

I would like to persist the session so I don't have to look up AD for every API call

  • For this while requesting the token, you can ask for offline scope so the Identity server will provide the Refresh Token with Access Token so you don't need to ask for AD again and again.

I would like single sign on. On the Windows machines, I don't require them to enter user and pass as I already can retrieve their username using Windows Authentication.

  • For this one, you can have your Identity sever trust the WSFederation for windows Authentication.

So basically you need to setup Identity server that will provide you with the token and the REST API will use that token to verify claims to return the correct information back to the user.

Answers 2

I am not sure what you expect exactly. Anyway, first I'm gonna reformulate your question with requirements:

  • you accounts and role are in active directory
  • you want to manage roles based on an active directory group
  • you want anybody whatever the system (windows, linux, mac, mobile...) to connect on your application using the same authentication
  • you want to avoid your AD to be hit constantly (not at any call for example)
  • if the user is connected on an application that uses the authentication system, he doesn't have to do it so again on another application that uses the same authentication system

If these requirements are yours. I believe the only standard (and clean) solution is to use OAuth. I'm not gonna go in detailed description of OAuth, but this authentication protocol is the most standard one on the net (facebook, google, twitter...). Of course as you don't want to use facebook, google or twitter accounts in your business applications but your active directory accounts you'll have to install/setup/develop your OAuth identity provider using accounts of your active active directory server. Your choice will depend on how well you know ADFS protocol and its different flows (code, implicit, assersion) You have two solutions for it:

  • Use ADFS: install ADFS; it provides a OAuth portal that will work out of the box with asp.net mvc. This uses the code flow of OAuth that is the only OAuth flow supported by ADFS. For roles and its related AD groups, you'll have to map role claims with AD groups. (it's in the setup of adfs, you'll find many tutos on the net). You'll find lot of tutos as well about how to use ADFS with asp.net mvc/asp.net webapi. I mention .net here, but every technology has an implementation for OAuth authentication (nodeJs/express, php, java...).
  • Use thinktecture identity server (.net technology). This will provide all the foundation to implement a custom identity server with the least effort: http://www.thinktecture.com/identityserver / https://github.com/IdentityServer/IdentityServer3. It contains an addin to plug it's accounts to active directory. With this, you can use implicit and assertion flows.
  • Use oauth2orize (for nodeJs): https://www.npmjs.com/package/oauth2orize. This will permit you to make the same than thinktecture identity server but in nodeJs. Apparently you'll have to make all the wirering with ad manually. With this, you can use implicit flows (not sure about assertion flows).

At application side, most of frameworks can authenticate easily using OAuth with a lot of existing frameworks. For example, even if you make a single page application, you can use adal.js or adal.js for angular if you use angular. As I mentioned above, all this is taken in change by asp.net mvc/webapi out of the box but I know it's the case for other server technologies. If you have more questions, don't hesitate as I'm not sure of what you expect exactly.

Read More

Friday, July 8, 2016

How to be notified when the user deny fitness data?

Leave a Comment

I can check if the user authorized fitness data using -[CMMotionActivityManager queryActivityStartingFromDate:toDate:toQueue:withHandler:] and check for an error (CMErrorNotAuthorized or CMErrorMotionActivityNotAuthorized) in the handler.

If the user go to Privacy settings and deny my app, the app is killed and when I relaunch it, everything works fine.

If the user go to Privacy settings and deny fitness data globally, the app is not killed and the check using the method above does not report any error !

I have to target iOS 8 so I can't use +[CMSensorRecorder isAuthorizedForRecording].

Have you any reliable way of solving this problem ? It is quite annoying to have a nice API for location authorization but not for this one!

1 Answers

Answers 1

Accordingly to Apple's docs, + (BOOL)isAuthorizedForRecording is only available on in iOS 9.0 and later, so you can not use it on iOS8.

Read More

Monday, March 14, 2016

Restrict cloudfront signed url (GET Request) to be accessed by my mobile application

Leave a Comment

I am trying to serve video files using Amazon cloudfront to my app users using signed urls. I have created the signed urls using the documentation and it works perfectly well. The url generated has the signature, expires and keypair_id.

issues

What I am trying to achieve is to serve the video files to the user only when the request is coming in from my particular mobile application. I am looking for a solution to authorize the request (on a signed url) on the cloudfront side.

So if a user tries to access the signed url using our mobile app, we would want to serve the content but if the url is accessed from either web or any other mobile client we would like to raise an authorization error or 404.

I have went through the documentation and a couple blogs looking to achieve the above and everyone has pointed me in the direction to use signed urls which I already am. But the urls are still accessible directly via the browser.

Also I would like to know, why does a signed url has signature as a GET parameter, as if the signature is removed the content is still accessible using the url without the get query params.

Signed Url: http://d2z7g8y6l5f1j0.cloudfront.net/test_upload.mp4?Expires=1456828601&Signature=R3tljkRxGM9se2S4IJT908sT2BBGNJkpWE9IE-v1GAt-QY0WcaEVEY-OYvSSlhFK1ueNcWhgAscJQ7J~qUKZUt3XS5raKU3kj9STKYYzCemRRm1j5DE8XfhjRKRggSSw138F0lr~tDt~TLoJ7Pj9NNvoGl42jNNLaET7~d9pkAGAh-sNpoS1gz~d0CZTo41ZTFMIzshgZNxrWpCOR0PrLHfRALy2H9-Z9w4XfU4v66WEseVQ3FWyeXFyV0UO2S-KIXbe1ODiHFC6Ae6AJlWzoFfIGAxiLymmtUMJgeQHnu80u97ysMbbNYvek-S0tQBkkID3zC~tDQH~EjXPYcNUbA__&Key-Pair-Id=APKAINPV56WSGDECRTPQ  ^^^ Serves the content  Original Url: http://d2z7g8y6l5f1j0.cloudfront.net/test_upload.mp4  ^^^ Still serves the content 

What's the difference in the above urls ?

Further Issue

The signed url that I have generated is still serving the content so what is the point of the expires GET query parameter, or the issue is that I have made the url correctly or not.

I followed the following method to generate my signed url:

from boto.cloudfront import CloudFrontConnection from boto.cloudfront.distribution import Distribution  # establish cloudfront connection cloudfront_connection = CloudFrontConnection('AWS_KEY', 'AWS_SECRET') expiry_time = int(time.time() + 3000)  #get the distribution distribution = Distribution(connection = cloudfront_connection, domain_name = '<specified_domain_name>', 'id' = '<specified distribution id>')  #create signed url signed_url = distribution.create_signed_url(url = '<cloudfront_url>', keypair_id = '<cloudfront keypair_id>', expire_time = expiry_time, private_key_file = open('<location>', 'r')) 

1 Answers

Answers 1

I have went through the documentation and a couple blogs looking to achieve the above and everyone has pointed me in the direction to use signed urls which I already am. But the urls are still accessible directly via the browser.

Perhaps you have a misunderstanding of the signed URL feature. Any client that has the URL can access the content - there's nothing limiting it to a specific mobile browser or desktop browser or anything else. So long as the URL is valid (e.g. is within the validity period/has not expired, and is within the IP range that you specified, etc), any client will be allowed access.

Your application should generate the signed URL in real time when the user requests it, and it should expire within a time frame that is acceptable to you. This is explained in the docs under How Signed URLs work.

Also I would like to know, why does a signed url has signature as a GET parameter, as if the signature is removed the content is still accessible using the url without the get query params.

You need to use set up a cache behavior that restricts access to requestors that have valid signed URLs. To summarize, when you set up the distribution, you can configure various cache behaviors based on the path that the user is requesting.

This topic is a bit buried in the documentation. See the docs on Cache Behavior Settings, and in particular the Path Pattern and Restrict Viewer Access subsections.

Read More