initializing private variable for subsequent usage - f#

Can you initialize a private value in a module, and then later call another function to read the value? I'm getting an empty string though.
data/Credentials.fs
type Credentials = {
mutable clientId: string;
}
Authentication.fs
module Authentication =
let private credentials = {
clientId = "old";
}
let init (claims: Credentials) =
credentials.clientId <- claims.clientId // updating value
let requestToken =
printfn "reading %s\n" credentials.clientId // reading updated value
AuthenticationTest.fs
let credentials = {
clientId = "new";
}
init credentials // set credentials
requestToken // read credentials
Expected output:
reading new
Actual Output:
reading old

requestToken is defined as variable, which contains result of printfn "reading %s\n" credentials.clientId. What you want is probably
let requestToken () =
printfn "reading %s\n" credentials.clientId
...
requestToken ()

Related

Create and sign JWT in Scala for Apple AppStore Connect

i want to create a JWT in a scala application for talking to the Apple's AppStore Connect api. i'm following the guide here
i'm getting an invalid signature on jwt.io when creating a JWT with the below code. a request to appstore connect results in a 401
i can verify that the JWT encodes the header and payload correctly on http://jwt.io
looking at this library, i think i'm selecting the correct curve algorithm:
After creating the token, one must sign it with an Apple-provided private key, using the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve and the SHA-256 hash algorithm, or ES256.
i'm not sure what is wrong - maybe i'm not generating the S value correctly?
def generateJWT(): String = {
val privateKeyBytes: Array[Byte] =
Base64.getDecoder.decode("base64 representation of private key")
val S = BigInt(privateKeyBytes)
val curveParams = ECNamedCurveTable.getParameterSpec("P-256")
val curveSpec: ECParameterSpec =
new ECNamedCurveSpec("P-256", curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
val privateSpec = new ECPrivateKeySpec(S.underlying, curveSpec)
val privateKey =
KeyFactory.getInstance("EC").generatePrivate(privateSpec)
val unixTimestamp: Long = Instant.now.getEpochSecond
val fiveMins = unixTimestamp.toInt + 300
val header = Map[String, Object](
"kid" -> "appstore connect Key Identifier",
"typ" -> "JWT",
"alg" -> "ES256"
)
val payload = Map[String, Object](
"iss" -> "issuer ID from the API Keys page in App Store Connect",
"aud" -> "appstoreconnect-v1",
"exp" -> new Integer(fiveMins)
)
Jwts
.builder()
.setHeaderParams(header.asJava)
.setClaims(payload.asJava)
.signWith(SignatureAlgorithm.ES256, privateKey)
.compact()
}
I can suggest two things to try out:
JwtBuilder signWith(SignatureAlgorithm var1, Key var2) is deprecated. Can you try using JwtBuilder signWith(Key var1, SignatureAlgorithm var2) , and see if that succeeds?
If not, you can try using bountycastle , which does work for me. Following is the code snippet for getting the private key.
def getPrivateKey(): PrivateKey = {
val pemParser = new PEMParser(new FileReader(<Your Apple-AuthKey file with extension .p8>))
val converter = new JcaPEMKeyConverter
val privateKeyInfo = pemParser.readObject.asInstanceOf[PrivateKeyInfo]
val pKey = converter.getPrivateKey(privateKeyInfo)
pemParser.close()
pKey
}

The generated JSON Web Token is not accepted by Google API Service

I have created a service account and downloaded my JSON Credential on Google Cloud Platform. I need to make REST POST call in .NET to DialogFlow Service API. At this moment, I can do it only with a generated token in PowerShell. Since, I need to do it all from script, I need to generate a JWT to pass as my bearer in my REST call. My Problem is that the generated JWT is not honored by Google.
I get my response in PowerShell based on this doc page and I replicate sample codes from this doc page to create my JWT.
public static string GetSignedJwt(string emailClient, string
dialogueFlowServiceApi, string privateKeyId, string privateKey, string
jsonPath)
{
// to get unix time in seconds
var unixTimeSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// start time of Unix system
var origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
// adding milliseconds to reach the current time, it will be used for issueAt time
var nowDataTime = origin.AddSeconds(unixTimeSeconds);
// one hour after the current time, it will be used for expiration time
var oneHourFromNow = nowDataTime.AddSeconds(3600);
// holder of signed json web token that we will return at the end
var signedJwt = "";
try
{
// create our payload for Jwt
var payload = new Dictionary<string, object>
{
{"iss", emailClient},
{"sub", emailClient},
{"aud", dialogueFlowServiceApi},
{"iat", nowDataTime},
{"exp", oneHourFromNow}
};
// create our additional headers
var extraHeaders = new Dictionary<string, object>
{
{"kid", privateKeyId}
};
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
signedJwt = encoder.Encode(extraHeaders, payload, privateKey);
}
catch (Exception e)
{
Console.WriteLine(e);
// return null if there has been any error
return null;
}
finally
{
Console.WriteLine(signedJwt);
}
return signedJwt;
}
Notice that, it is needed to be signed in RSA256 by passing public and private keys, as Google did it in Java sample snippet, however, my equivalent in .Net gives me only Object reference not set to an instance of an object when I use that algorithm:
var key = RSA.Create(privateKey);
IJwtAlgorithm algorithm = new RS256Algorithm(null, key);
IJsonSerializer serializer = new JsonNetSerializer();
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
signedJwt = encoder.Encode(extraHeaders, payload, privateKey);
Besides of correct keys, I am using https://dialogflow.googleapis.com/google.cloud.dialogflow.v2beta1.Intents as dialogFlow service API key.
I expect it that my generated JWT gets accepted, however it is rejected by Google.
1) You are using the wrong algorithm
Change this line of code:
IJwtAlgorithm algorithm = new RS256Algorithm(null, key);
To this:
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
2) For the JWT headers:
var additional_headers = new Dictionary<string, object>
{
{ "kid", privateKeyId },
{ "alg", "RS256" },
{ "typ", "JWT" }
};
3) Your JWT Payload does not include a scope. I am not sure which scope you need but here is an example. Add this to the payload before creating the JWT:
string scope = "https://www.googleapis.com/auth/cloud-platform";
var payload = new Dictionary<string, object>
{
{"scope", scope},
{"iss", emailClient},
{"sub", emailClient},
{"aud", dialogueFlowServiceApi},
{"iat", nowDataTime},
{"exp", oneHourFromNow}
};
4) For most Google APIs (not all) you also need to exchange the Signed JWT for a Google OAuth Access Token:
public static string AuthorizeToken(string token, string auth_url)
{
var client = new WebClient();
client.Encoding = Encoding.UTF8;
var content = new NameValueCollection();
// Request a "Bearer" access token
content["assertion"] = token;
content["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
var response = client.UploadValues(auth_url, "POST", content);
return Encoding.UTF8.GetString(response);
}
The Authorization URL for above:
string auth_url = "https://www.googleapis.com/oauth2/v4/token";

How can I implement a strategy pattern for returning a structure that's declared private?

How can I implement a strategy pattern for returning a structure that's declared private?
Or translated...
How do I restrict the creation of a private structure to more than one function?
I want to implement an IOlogin interpreter and a MockLogin interpreter for a user login operation. The two functions should return a value of type AuthenticatedManager.
Getting started, I wanted to define a type in a module like this:
module Specification =
type AuthenticatedManager = private { Name:string }
The code above is meant to restrict the creation of an AuthenticatedManager.
I want to reference AuthenticatedManager in a separate module:
module Mock =
open Specification
let username = Username "test_manager"
let password = Password "123"
let invalidPassword = Password "invalid password"
let login username' password' : Result<AuthenticatedManager,Username*string> =
if ( username',password') = ( username,password )
then Ok { Name="authenticated manager" } // compile error
else Error ( username',"Failed to login" )
I know that the compile error stems from me trying to reference a private structure outside of the module that I declared it in. However, I believe it makes sense to have separate libraries to accommodate interpreters for this type of operation.
You should define a module for each type with a private constructor and have create and value functions for the type in that module. The module should be in the same compilation unit as the type, so it can access the private constructor. The following is a simple example of a pattern I use all the time:
[<Struct>] type Username = private Username of string
// Make one module for each type
module Username =
let create = function // Use whatever the real business rules are here
| username when not <| String.IsNullOrEmpty(username) -> Ok <| Username username
| _ -> Error "Username must not be blank"
let value (Username username) = username
Then, anywhere you need a Username, you call the create function that has access to the private constructor, and it validates the data and builds it for you. Likewise, anywhere you need to extract the raw string from the Username, you use the value function.
I added a strategy function (i.e. *AuthenticationStrategy *) to the same containing module that the private constructor was declared in.
I was then able to compile without any issues.
Specification
namespace Access.Specification
type Username = Username of string
type Password = Password of string
type AuthenticationStrategy = Username -> Password -> unit -> bool
type AuthenticatedManager = private { Name:string }
let authenticate username password strategy : AuthenticatedManager option =
if strategy username password ()
then Some { Name= "username" }
else None
Mock
let login username' password' : Result<AuthenticatedManager,Username*string> =
let strategy username'' password'' () =
if ( username'',password'') = ( username,password )
then true
else false
authenticate username' password' strategy
|> function
| Some manager -> Ok manager
| None -> Error <| (username',"Login failed")
Gateway
module Access.Gateway
open Mobile.Core
let login username password : Result<AuthenticatedManager,Username*string> =
let strategy username' password' () =
// IO Logic goes here...
true
authenticate username password strategy
|> function
| Some manager -> Ok manager
| None -> Error <| (username,"Login failed")
Appendix
module AppLogic.Configuration
open Access
open Access.Specification.Login
open Access.Specification
open TestAPI
type Environment = DEV | QA | PROD
type Dependencies = {
Environment: Environment
ServerLogin: Login.Attempt
ForgotPassword: Login.PasswordRequest
}
let configure = function
| DEV -> { Environment= DEV
ServerLogin= { Login= Mock.login; Endpoint= Endpoint "n/a" }
ForgotPassword= { Forgot= Mock.forgotPassword; Endpoint= Endpoint "n/a" }
}
| QA -> { Environment= QA
ServerLogin= { Login= Gateway.login; Endpoint= Endpoint "http://..." }
ForgotPassword= { Forgot= Mock.forgotPassword; Endpoint= Endpoint "http://..." }
}
| PROD -> { Environment= PROD
ServerLogin= { Login= Gateway.login; Endpoint= Endpoint "http://..." }
ForgotPassword= { Forgot= Mock.forgotPassword; Endpoint= Endpoint "http://..." }
}

Parsing Tweets with akka-streams

Im using the following code to connect to Twitter and get Tweets, however Im not able to create JsValue. If only map with byteString.utf8String I can see the strings. But when I add framing i get an error:
Read 7925 bytes which is more than 1000 without seeing a line terminator
No matter how long i make the input im still getting this error. What do I need to change to get a stream of JsValue in my websocket?
Information about how one is expected to consume twitter streams can be found here
#Singleton
class TwitterController #Inject() (ws: WSClient, conf: Configuration) {
def tweets = WebSocket.accept[JsValue,JsValue] { implicit request =>
Flow.fromSinkAndSource(Sink.ignore, queryToSource("cat"))
}
def queryToSource(keyword: String): Source[JsValue, NotUsed] = {
val url = "https://stream.twitter.com/1.1/statuses/filter.json"
credentials.map { case (consumerKey, requestToken) =>
val request = ws.url(url)
.sign(OAuthCalculator(consumerKey, requestToken))
.withQueryString("track" -> keyword)
.withMethod("GET")
streamResponse(request)
.via(Framing.delimiter(ByteString("\r\n"), maximumFrameLength = 1000, allowTruncation = true))
.map { byteString =>
Json.parse(byteString.utf8String)
// byteString.utf8String
}
} getOrElse {
Source.single(Json.parse("Twitter credentials missing"))
}
}
private def streamResponse(request:WSRequest): Source[ByteString, NotUsed] = Source.fromFuture(request.stream()).flatMapConcat(_.body)
lazy val credentials: Option[(ConsumerKey, RequestToken)] = for {
apiKey <- conf.getString("twitter.apiKey")
apiSecret <- conf.getString("twitter.apiSecret")
token <- conf.getString("twitter.token")
tokenSecret <- conf.getString("twitter.tokenSecret")
} yield (
ConsumerKey(apiKey, apiSecret),
RequestToken(token, tokenSecret)
)
}

LinkedIn Oauth2 throws exception using Scribejava

This is the code from the tutorial Getting Started and I'm only trying it, nothing else is running.
public class Launch {
private static final String url =
"http://api.linkedin.com/v1/people/~/connections:(id,first-name,last-name,email-address,picture-url)";
private static final String url2 =
"http://api.linkedin.com/v1/people/~/connections:(id,first-name,last-name)";
public Launch() {
OAuthService service = new ServiceBuilder()
.provider(LinkedInApi.class)
.apiKey("xxxx")
.apiSecret("xxxx")
.build();
Token requestToken = service.getRequestToken();
String authUrl = service.getAuthorizationUrl(requestToken);
Verifier v = new Verifier("verifier you got from the user");
Token accessToken = service.getAccessToken(requestToken, v); // the requestToken you had from step 2
OAuthRequest request = new OAuthRequest(Verb.GET, url2);
service.signRequest(accessToken, request); // the access token from step 4
Response response = request.send();
System.out.println(response.getBody());
}
In my controller I have:
#View
public Response.Content index(){
Launch launch = new Launch();
return index.ok();}
and when I try to launch it, it gives me this error:
org.scribe.exceptions.OAuthException: Response body is incorrect. Can't extract token and secret from this: 'oauth_problem=permission_unknown'
Found the solution: changed the code to add Scanner in = new Scanner(System.in); after the ServiceBuilder declaration to use it in Verifier verifier = new Verifier(in.nextLine());
And also, put manually the url found in the terminal which is the result of System.out.println(service.getAuthorizationUrl(requestToken));
It's a temporary url, but the only way this works till now.

Resources